From fc65c2518cefb18b09dcfcad8b06d7283ad3523b Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Wed, 3 Feb 2016 23:55:46 +0000 Subject: [PATCH] Fplay: h264 hardware decoding and output. git-svn-id: svn://kolibrios.org@6133 a494cfbc-eb01-0410-851d-a64ba20cac60 --- contrib/media/fplay/audio.c | 1 - contrib/media/fplay/fplay.c | 26 +- contrib/media/fplay/fplay.h | 49 ++- contrib/media/fplay/list.h | 579 ++++++++++++++++++++++++++++ contrib/media/fplay/vaapi.c | 291 +++++++------- contrib/media/fplay/video.c | 365 +++++++++--------- contrib/media/fplay/winlib/link.h | 2 +- contrib/media/fplay/winlib/window.c | 3 + 8 files changed, 966 insertions(+), 350 deletions(-) create mode 100644 contrib/media/fplay/list.h diff --git a/contrib/media/fplay/audio.c b/contrib/media/fplay/audio.c index abe399a886..34119993ef 100644 --- a/contrib/media/fplay/audio.c +++ b/contrib/media/fplay/audio.c @@ -417,4 +417,3 @@ exit_whith_error: return -1; }; - diff --git a/contrib/media/fplay/fplay.c b/contrib/media/fplay/fplay.c index 44ff91fa4c..c5656832ec 100644 --- a/contrib/media/fplay/fplay.c +++ b/contrib/media/fplay/fplay.c @@ -26,9 +26,6 @@ volatile enum player_state sound_state = STOP; uint32_t win_width, win_height; - -AVFrame *pFrame; - int have_sound = 0; uint8_t *decoder_buffer; @@ -147,6 +144,15 @@ int main( int argc, char *argv[]) printf("codec id %x name %s\n",vst.vCtx->codec_id, vst.vCodec->name); printf("ctx->pix_fmt %d\n", vst.vCtx->pix_fmt); + INIT_LIST_HEAD(&vst.input_list); + INIT_LIST_HEAD(&vst.output_list); + mutex_init(&vst.q_video.lock); + mutex_init(&vst.q_audio.lock); + mutex_init(&vst.gpu_lock); + mutex_init(&vst.decoder_lock); + mutex_init(&vst.input_lock); + mutex_init(&vst.output_lock); + if(vst.vCodec == NULL) { printf("Unsupported codec with id %d for input stream %d\n", @@ -166,10 +172,6 @@ int main( int argc, char *argv[]) printf("ctx->pix_fmt %d\n", vst.vCtx->pix_fmt); - mutex_init(&vst.q_video.lock); - mutex_init(&vst.q_audio.lock); - mutex_init(&vst.gpu_lock); - if (vst.aCtx->channels > 0) vst.aCtx->request_channels = FFMIN(2, vst.aCtx->channels); else @@ -224,10 +226,9 @@ int main( int argc, char *argv[]) if(!init_video(&vst)) return 0; - decoder(&vst); + mutex_lock_timeout(&vst.decoder_lock, 3000); - // Free the YUV frame - av_free(pFrame); + decoder(&vst); //__asm__ __volatile__("int3"); @@ -241,7 +242,7 @@ int main( int argc, char *argv[]) mutex_destroy(&vst.q_video.lock); mutex_destroy(&vst.q_audio.lock); - + mutex_destroy(&vst.decoder_lock); return 0; } @@ -334,8 +335,7 @@ void decoder(vst_t* vst) } decode_video(vst); ret = decode_audio(vst->aCtx, &vst->q_audio); - }while(astream.count < resampler_size*2 && - ret == 1); + }while(astream.count < resampler_size*2 && ret == 1); sound_state = PREPARE; decoder_state = PLAY; diff --git a/contrib/media/fplay/fplay.h b/contrib/media/fplay/fplay.h index 75c59ec78b..e6d9098111 100644 --- a/contrib/media/fplay/fplay.h +++ b/contrib/media/fplay/fplay.h @@ -1,6 +1,7 @@ #include -#include "pixlib3.h" +#include +#include "list.h" #define BLACK_MAGIC_SOUND #define BLACK_MAGIC_VIDEO @@ -18,10 +19,15 @@ typedef struct vstate vst_t; typedef struct { + struct list_head list; enum AVPixelFormat format; AVPicture picture; - int planar; + planar_t* planar; + int is_hw_pic; + int index; double pts; + double pkt_pts; + double pkt_dts; volatile int ready; }vframe_t; @@ -53,7 +59,7 @@ struct render EMPTY, INIT }state; enum win_state win_state; - void (*draw)(render_t *render, AVPicture *picture); + void (*draw)(render_t *render, vframe_t *vframe); }; enum player_state @@ -105,26 +111,31 @@ typedef struct { int put_packet(queue_t *q, AVPacket *pkt); int get_packet(queue_t *q, AVPacket *pkt); +#define HWDEC_NUM_SURFACES 16 struct vstate { - AVFormatContext *fCtx; /* format context */ - AVCodecContext *vCtx; /* video decoder context */ - AVCodecContext *aCtx; /* audio decoder context */ - AVCodec *vCodec; /* video codec */ - AVCodec *aCodec; /* audio codec */ - int vStream; /* video stream index */ - int aStream; /* audio stream index */ + AVFormatContext *fCtx; /* format context */ + AVCodecContext *vCtx; /* video decoder context */ + AVCodecContext *aCtx; /* audio decoder context */ + AVCodec *vCodec; /* video codec */ + AVCodec *aCodec; /* audio codec */ + int vStream; /* video stream index */ + int aStream; /* audio stream index */ - queue_t q_video; /* video packets queue */ - queue_t q_audio; /* audio packets queue */ + queue_t q_video; /* video packets queue */ + queue_t q_audio; /* audio packets queue */ - mutex_t gpu_lock; /* gpu access lock. libdrm not yet thread safe :( */ + mutex_t gpu_lock; /* gpu access lock. libdrm not yet thread safe :( */ + mutex_t decoder_lock; - vframe_t vframe[4]; /* decoder workset */ - int vfx; /* index of decoded frame */ - int dfx; /* index of renderd frame */ - void *hwCtx; /* hardware context */ - int hwdec; /* hardware decoder */ + mutex_t input_lock; + mutex_t output_lock; + struct list_head input_list; + struct list_head output_list; + + vframe_t *decoder_frame; + void *hwCtx; /* hardware context */ + int hwdec; /* hardware decoder */ }; @@ -165,7 +176,7 @@ static inline void GetNotify(void *event) ::"a"(68),"b"(14),"c"(event)); } -void va_convert_picture(vst_t *vst, int width, int height, AVPicture *pic); +void va_create_planar(vst_t *vst, vframe_t *vframe); int init_fontlib(); char *get_moviefile(); diff --git a/contrib/media/fplay/list.h b/contrib/media/fplay/list.h new file mode 100644 index 0000000000..b64bc3bf4d --- /dev/null +++ b/contrib/media/fplay/list.h @@ -0,0 +1,579 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#define LIST_POISON1 ((void *) 0x80000000) +#define LIST_POISON2 ((void *) 0x80001000) + + +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - __builtin_offsetof(type,member) );}) + +struct list_head +{ + struct list_head *next; + struct list_head *prev; +}; + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** + * list_first_entry_or_null - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, __typeof__(*(pos)), member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, __typeof__(*(pos)), member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, __typeof__(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, __typeof__(*pos), member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_head within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, __typeof__(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, __typeof__(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_last_entry(head, __typeof__(*pos), member), \ + n = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_prev_entry(n, member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_head within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) \ + n = list_next_entry(pos, member) + +#endif diff --git a/contrib/media/fplay/vaapi.c b/contrib/media/fplay/vaapi.c index e305a0507f..3e21b89b18 100644 --- a/contrib/media/fplay/vaapi.c +++ b/contrib/media/fplay/vaapi.c @@ -17,7 +17,7 @@ struct hw_profile { enum AVCodecID av_codec; int ff_profile; - uint64_t va_profile; + VAProfile va_profile; }; @@ -39,7 +39,7 @@ struct hw_profile static int drm_fd = 0; static struct vaapi_context *v_context; -static VASurfaceID v_surface_id[4]; +static VASurfaceID v_surface_id[HWDEC_NUM_SURFACES]; #define HAS_HEVC VA_CHECK_VERSION(0, 38, 0) #define HAS_VP9 (VA_CHECK_VERSION(0, 38, 1) && defined(FF_PROFILE_VP9_0)) @@ -48,7 +48,7 @@ static VASurfaceID v_surface_id[4]; {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile, \ VAProfile ## vdp_profile} -static const struct hw_profile profiles[] = { +static const struct hw_profile hw_profiles[] = { PE(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main), PE(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple), PE(MPEG4, MPEG4_ADVANCED_SIMPLE, MPEG4AdvancedSimple), @@ -75,8 +75,8 @@ static const struct hw_profile profiles[] = { int va_check_codec_support(enum AVCodecID id) { - for (int n = 0; profiles[n].av_codec; n++) { - if (profiles[n].av_codec == id) + for (int n = 0; hw_profiles[n].av_codec; n++) { + if (hw_profiles[n].av_codec == id) return 1; } return 0; @@ -219,9 +219,9 @@ void *vaapi_init(VADisplay display) if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL) goto error; - vaapi->display = display; - vaapi->config_id = VA_INVALID_ID; - vaapi->context_id = VA_INVALID_ID; + vaapi->display = display; + vaapi->config_id = VA_INVALID_ID; + vaapi->context_id = VA_INVALID_ID; v_context = vaapi; @@ -281,7 +281,7 @@ static int has_entrypoint(struct vaapi_context *vaapi, VAProfile profile, VAEntr return 0; } -static int vaapi_init_decoder(VAProfile profile, +static int vaapi_init_decoder(VAProfile profile, VAEntrypoint entrypoint, unsigned int picture_width, unsigned int picture_height) @@ -343,8 +343,7 @@ ENTER(); printf("vaCreateSurfaces %dx%d\n",picture_width,picture_height); status = vaCreateSurfaces(vaapi->display, VA_RT_FORMAT_YUV420, picture_width, picture_height, - v_surface_id,4,NULL,0); - printf("v_surface_id_3 %x\n", v_surface_id[3]); + v_surface_id,HWDEC_NUM_SURFACES,NULL,0); if (!vaapi_check_status(status, "vaCreateSurfaces()")) { FAIL(); @@ -379,7 +378,7 @@ ENTER(); status = vaCreateContext(vaapi->display, config_id, picture_width, picture_height, VA_PROGRESSIVE, - v_surface_id, 4, + v_surface_id, HWDEC_NUM_SURFACES, &context_id); if (!vaapi_check_status(status, "vaCreateContext()")) { @@ -387,8 +386,8 @@ ENTER(); return -1; }; - vaapi->config_id = config_id; - vaapi->context_id = context_id; + vaapi->config_id = config_id; + vaapi->context_id = context_id; LEAVE(); return 0; } @@ -397,48 +396,38 @@ ENTER(); static enum PixelFormat get_format(struct AVCodecContext *avctx, const enum AVPixelFormat *fmt) { - int i, profile; + VAProfile profile = VAProfileNone; ENTER(); -// for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) -// printf(" %s", av_get_pix_fmt_name(fmt[i])); + for (int i = 0; fmt[i] != PIX_FMT_NONE; i++) + { + enum AVCodecID codec = avctx->codec_id; - for (i = 0; fmt[i] != PIX_FMT_NONE; i++) { - printf("pixformat %x\n", fmt[i]); if (fmt[i] != AV_PIX_FMT_VAAPI_VLD) continue; - switch (avctx->codec_id) + if (codec == AV_CODEC_ID_H264) { - case CODEC_ID_MPEG2VIDEO: - profile = VAProfileMPEG2Main; - break; - case CODEC_ID_MPEG4: - case CODEC_ID_H263: - profile = VAProfileMPEG4AdvancedSimple; - break; - case CODEC_ID_H264: - profile = VAProfileH264High; - break; - case CODEC_ID_WMV3: - profile = VAProfileVC1Main; - break; - case CODEC_ID_VC1: - profile = VAProfileVC1Advanced; - break; - default: - profile = -1; - break; - } - if (profile >= 0) { - if (vaapi_init_decoder(profile, VAEntrypointVLD, avctx->width, avctx->height) == 0) + if (profile == FF_PROFILE_H264_CONSTRAINED_BASELINE) + profile = FF_PROFILE_H264_MAIN; + }; + + for (int n = 0; hw_profiles[n].av_codec; n++) + { + if (hw_profiles[n].av_codec == codec && + hw_profiles[n].ff_profile == avctx->profile) { - avctx->hwaccel_context = v_context; - LEAVE(); - return fmt[i]; ; + profile = hw_profiles[n].va_profile; + if (vaapi_init_decoder(profile, VAEntrypointVLD, avctx->width, avctx->height) == 0) + { + avctx->hwaccel_context = v_context; + LEAVE(); + return fmt[i]; ; + } } } + } FAIL(); return PIX_FMT_NONE; @@ -454,16 +443,15 @@ struct av_surface static void av_release_buffer(void *opaque, uint8_t *data) { struct av_surface surface = *(struct av_surface*)data; -// VDPAUContext *ctx = opaque; - -// ctx->video_surface_destroy(surface); av_freep(&data); } static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags) { vst_t *vst = (vst_t*)avctx->opaque; - void *surface = (void *)(uintptr_t)v_surface_id[vst->dfx]; + void *surface; + + surface = (void *)(uintptr_t)v_surface_id[vst->decoder_frame->index]; pic->data[3] = surface; @@ -493,20 +481,16 @@ int fplay_init_context(vst_t *vst) if(vst->hwCtx != NULL) { - for(int i = 0; i < 4; i++) + for(int i = 0; i < HWDEC_NUM_SURFACES; i++) { - int ret; + vframe_t *vframe = calloc(1, sizeof(*vframe)); - ret = avpicture_alloc(&vst->vframe[i].picture, AV_PIX_FMT_BGRA, - vst->vCtx->width, vst->vCtx->height); - if ( ret != 0 ) - { - printf("Cannot alloc video buffer\n\r"); - return ret; - }; - vst->vframe[i].format = AV_PIX_FMT_BGRA; - vst->vframe[i].pts = 0; - vst->vframe[i].ready = 0; + vframe->format = AV_PIX_FMT_NONE; + vframe->is_hw_pic = 1; + vframe->index = i; + vframe->pts = 0; + vframe->ready = 0; + list_add_tail(&vframe->list, &vst->input_list); }; vst->hwdec = 1; @@ -520,107 +504,154 @@ int fplay_init_context(vst_t *vst) vst->hwdec = 0; - for(int i = 0; i < 4; i++) + for(int i = 0; i < HWDEC_NUM_SURFACES; i++) { + vframe_t *vframe; int ret; - ret = avpicture_alloc(&vst->vframe[i].picture, vst->vCtx->pix_fmt, + vframe = calloc(1, sizeof(*vframe)); + + ret = avpicture_alloc(&vframe->picture, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); if ( ret != 0 ) { printf("Cannot alloc video buffer\n\r"); return ret; }; - vst->vframe[i].format = vst->vCtx->pix_fmt; - vst->vframe[i].pts = 0; - vst->vframe[i].ready = 0; + vframe->format = vst->vCtx->pix_fmt; + vframe->index = i; + vframe->pts = 0; + vframe->ready = 0; + list_add_tail(&vframe->list, &vst->input_list); }; return 0; } -struct SwsContext *vacvt_ctx; +#define EGL_TEXTURE_Y_U_V_WL 0x31D7 +#define EGL_TEXTURE_Y_UV_WL 0x31D8 +#define EGL_TEXTURE_Y_XUXV_WL 0x31D9 -void va_convert_picture(vst_t *vst, int width, int height, AVPicture *pic) +enum wl_drm_format { + WL_DRM_FORMAT_C8 = 0x20203843, + WL_DRM_FORMAT_RGB332 = 0x38424752, + WL_DRM_FORMAT_BGR233 = 0x38524742, + WL_DRM_FORMAT_XRGB4444 = 0x32315258, + WL_DRM_FORMAT_XBGR4444 = 0x32314258, + WL_DRM_FORMAT_RGBX4444 = 0x32315852, + WL_DRM_FORMAT_BGRX4444 = 0x32315842, + WL_DRM_FORMAT_ARGB4444 = 0x32315241, + WL_DRM_FORMAT_ABGR4444 = 0x32314241, + WL_DRM_FORMAT_RGBA4444 = 0x32314152, + WL_DRM_FORMAT_BGRA4444 = 0x32314142, + WL_DRM_FORMAT_XRGB1555 = 0x35315258, + WL_DRM_FORMAT_XBGR1555 = 0x35314258, + WL_DRM_FORMAT_RGBX5551 = 0x35315852, + WL_DRM_FORMAT_BGRX5551 = 0x35315842, + WL_DRM_FORMAT_ARGB1555 = 0x35315241, + WL_DRM_FORMAT_ABGR1555 = 0x35314241, + WL_DRM_FORMAT_RGBA5551 = 0x35314152, + WL_DRM_FORMAT_BGRA5551 = 0x35314142, + WL_DRM_FORMAT_RGB565 = 0x36314752, + WL_DRM_FORMAT_BGR565 = 0x36314742, + WL_DRM_FORMAT_RGB888 = 0x34324752, + WL_DRM_FORMAT_BGR888 = 0x34324742, + WL_DRM_FORMAT_XRGB8888 = 0x34325258, + WL_DRM_FORMAT_XBGR8888 = 0x34324258, + WL_DRM_FORMAT_RGBX8888 = 0x34325852, + WL_DRM_FORMAT_BGRX8888 = 0x34325842, + WL_DRM_FORMAT_ARGB8888 = 0x34325241, + WL_DRM_FORMAT_ABGR8888 = 0x34324241, + WL_DRM_FORMAT_RGBA8888 = 0x34324152, + WL_DRM_FORMAT_BGRA8888 = 0x34324142, + WL_DRM_FORMAT_XRGB2101010 = 0x30335258, + WL_DRM_FORMAT_XBGR2101010 = 0x30334258, + WL_DRM_FORMAT_RGBX1010102 = 0x30335852, + WL_DRM_FORMAT_BGRX1010102 = 0x30335842, + WL_DRM_FORMAT_ARGB2101010 = 0x30335241, + WL_DRM_FORMAT_ABGR2101010 = 0x30334241, + WL_DRM_FORMAT_RGBA1010102 = 0x30334152, + WL_DRM_FORMAT_BGRA1010102 = 0x30334142, + WL_DRM_FORMAT_YUYV = 0x56595559, + WL_DRM_FORMAT_YVYU = 0x55595659, + WL_DRM_FORMAT_UYVY = 0x59565955, + WL_DRM_FORMAT_VYUY = 0x59555956, + WL_DRM_FORMAT_AYUV = 0x56555941, + WL_DRM_FORMAT_NV12 = 0x3231564e, + WL_DRM_FORMAT_NV21 = 0x3132564e, + WL_DRM_FORMAT_NV16 = 0x3631564e, + WL_DRM_FORMAT_NV61 = 0x3136564e, + WL_DRM_FORMAT_YUV410 = 0x39565559, + WL_DRM_FORMAT_YVU410 = 0x39555659, + WL_DRM_FORMAT_YUV411 = 0x31315559, + WL_DRM_FORMAT_YVU411 = 0x31315659, + WL_DRM_FORMAT_YUV420 = 0x32315559, + WL_DRM_FORMAT_YVU420 = 0x32315659, + WL_DRM_FORMAT_YUV422 = 0x36315559, + WL_DRM_FORMAT_YVU422 = 0x36315659, + WL_DRM_FORMAT_YUV444 = 0x34325559, + WL_DRM_FORMAT_YVU444 = 0x34325659, +}; + +void va_create_planar(vst_t *vst, vframe_t *vframe) { - uint8_t *src_data[4]; - int src_linesize[4]; + struct vaapi_context* const vaapi = v_context; + VABufferInfo info = {0}; + VAImage vaimage; VAStatus status; - uint8_t *vdata; - struct vaapi_context* const vaapi = v_context; + planar_t *planar; - vaSyncSurface(vaapi->display,v_surface_id[vst->dfx]); + vaSyncSurface(vaapi->display,v_surface_id[vframe->index]); - status = vaDeriveImage(vaapi->display,v_surface_id[vst->dfx],&vaimage); + if(vframe->format != AV_PIX_FMT_NONE) + return; + +ENTER(); + + status = vaDeriveImage(vaapi->display,v_surface_id[vframe->index],&vaimage); if (!vaapi_check_status(status, "vaDeriveImage()")) { FAIL(); return; }; - - static int once = 2; - - if(once && vst->dfx == 0) - { - VABufferInfo info = {0}; - - printf("vaDeriveImage: %x fourcc: %x\n" - "offset0: %d pitch0: %d\n" - "offset1: %d pitch1: %d\n" - "offset2: %d pitch2: %d\n", - vaimage.buf, vaimage.format.fourcc, - vaimage.offsets[0],vaimage.pitches[0], - vaimage.offsets[1],vaimage.pitches[1], - vaimage.offsets[2],vaimage.pitches[2]); - - info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; - status = vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info); - if (vaapi_check_status(status, "vaAcquireBufferHandle()")) - { - printf("vaAcquireBufferHandle: %x type: %x\n" - "mem type: %x mem size: %d\n", - info.handle, info.type, info.mem_type, info.mem_size); - - vaReleaseBufferHandle(vaapi->display, vaimage.buf); - } - once--; - }; - - src_linesize[0] = vaimage.pitches[0]; - src_linesize[1] = vaimage.pitches[1]; - src_linesize[2] = vaimage.pitches[2]; - src_linesize[3] = 0; - - status = vaMapBuffer(vaapi->display,vaimage.buf,(void **)&vdata); - if (!vaapi_check_status(status, "vaMapBuffer()")) +/* + printf("vaDeriveImage: %x fourcc: %x\n" + "offset0: %d pitch0: %d\n" + "offset1: %d pitch1: %d\n" + "offset2: %d pitch2: %d\n", + vaimage.buf, vaimage.format.fourcc, + vaimage.offsets[0],vaimage.pitches[0], + vaimage.offsets[1],vaimage.pitches[1], + vaimage.offsets[2],vaimage.pitches[2]); +*/ + info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; + status = vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info); + if (!vaapi_check_status(status, "vaAcquireBufferHandle()")) { + vaDestroyImage(vaapi->display, vaimage.image_id); FAIL(); return; }; - -// printf("vdata: %x offset0: %d offset1: %d offset2: %d\n", vdata, -// vaimage.offsets[0], -// vaimage.offsets[1], -// vaimage.offsets[2]); - - src_data[0] = vdata + vaimage.offsets[0]; - src_data[1] = vdata + vaimage.offsets[1]; - src_data[2] = vdata + vaimage.offsets[2]; - src_data[3] = 0; - - vacvt_ctx = sws_getCachedContext(vacvt_ctx, width, height, AV_PIX_FMT_NV12, - width, height, AV_PIX_FMT_BGRA, - SWS_FAST_BILINEAR, NULL, NULL, NULL); - if(vacvt_ctx == NULL) +/* + printf("vaAcquireBufferHandle: %x type: %x\n" + "mem type: %x mem size: %d\n", + info.handle, info.type, info.mem_type, info.mem_size); +*/ + planar = pxCreatePlanar(info.handle, WL_DRM_FORMAT_NV12, + vaimage.width, vaimage.height, + vaimage.offsets[0],vaimage.pitches[0], + vaimage.offsets[1],vaimage.pitches[1], + vaimage.offsets[2],vaimage.pitches[2]); + if(planar != NULL) { - printf("Cannot initialize the conversion context!\n"); - return ; + printf("create planar image\n",planar); + vframe->planar = planar; + vframe->format = AV_PIX_FMT_NV12; }; - sws_scale(vacvt_ctx, (const uint8_t* const *)src_data, src_linesize, 0, height, pic->data, pic->linesize); - - vaUnmapBuffer (vaapi->display, vaimage.buf); + vaReleaseBufferHandle(vaapi->display, vaimage.buf); vaDestroyImage(vaapi->display, vaimage.image_id); +LEAVE(); } diff --git a/contrib/media/fplay/video.c b/contrib/media/fplay/video.c index 31c5fb385d..c34607341e 100644 --- a/contrib/media/fplay/video.c +++ b/contrib/media/fplay/video.c @@ -28,35 +28,38 @@ struct SwsContext *cvt_ctx = NULL; render_t *main_render; -int width; -int height; - AVRational video_time_base; AVFrame *Frame; void get_client_rect(rect_t *rc); +void run_render(window_t *win, void *render); +void window_update_layout(window_t *win); +int fini_winlib(); void flush_video(vst_t *vst) { - int i; + vframe_t *vframe, *tmp; - for(i = 0; i < 4; i++) + mutex_lock(&vst->output_lock); + mutex_lock(&vst->input_lock); + + list_for_each_entry_safe(vframe, tmp, &vst->output_list, list) + list_move_tail(&vframe->list, &vst->input_list); + + list_for_each_entry(vframe, &vst->output_list, list) { - vst->vframe[i].pts = 0; - vst->vframe[i].ready = 0; - }; - vst->vfx = 0; - vst->dfx = 0; + vframe->pts = 0; + vframe->ready = 0; + } + + mutex_unlock(&vst->input_lock); + mutex_unlock(&vst->output_lock); + frames_count = 0; }; int init_video(vst_t *vst) { - int i; - - width = vst->vCtx->width; - height = vst->vCtx->height; - Frame = av_frame_alloc(); if ( Frame == NULL ) { @@ -64,81 +67,113 @@ int init_video(vst_t *vst) return 0; }; + mutex_lock(&vst->decoder_lock); + create_thread(video_thread, vst, 1024*1024); - delay(50); return 1; }; +static double dts = 0.0; + int decode_video(vst_t* vst) { AVPacket pkt; double pts; int frameFinished; - double current_clock; - if(vst->vframe[vst->dfx].ready != 0 ) - return -1; + if(vst->decoder_frame == NULL) + { + mutex_lock(&vst->input_lock); + if(list_empty(&vst->input_list)) + { + mutex_unlock(&vst->input_lock); + return -1; + } + vst->decoder_frame = list_first_entry(&vst->input_list, vframe_t, list); + list_del(&vst->decoder_frame->list); + mutex_unlock(&vst->input_lock); + + vframe_t *vframe = vst->decoder_frame; + }; if( get_packet(&vst->q_video, &pkt) == 0 ) - return 0; - -/* - current_clock = -90.0 + get_master_clock(); - - if( pkt.dts == AV_NOPTS_VALUE && - Frame->reordered_opaque != AV_NOPTS_VALUE) - pts = Frame->reordered_opaque; - else if(pkt.dts != AV_NOPTS_VALUE) - pts= pkt.dts; - else - pts= 0; - - - pts *= av_q2d(video_time_base)*1000.0; -*/ - if( 1 /*pts > current_clock*/) { - frameFinished = 0; - - vst->vCtx->reordered_opaque = pkt.pts; - - mutex_lock(&vst->gpu_lock); - - if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) - printf("video decoder error\n"); - - if(frameFinished) - { - AVPicture *dst_pic; - - if( pkt.dts == AV_NOPTS_VALUE && - Frame->reordered_opaque != AV_NOPTS_VALUE) - pts = Frame->reordered_opaque; - else if(pkt.dts != AV_NOPTS_VALUE) - pts = pkt.dts; - else - pts = 0; - - pts *= av_q2d(video_time_base); - - dst_pic = &vst->vframe[vst->dfx].picture; - - if(vst->hwdec == 0) - av_image_copy(dst_pic->data, dst_pic->linesize, - (const uint8_t**)Frame->data, - Frame->linesize, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); - else - va_convert_picture(vst, vst->vCtx->width, vst->vCtx->height, dst_pic); - - vst->vframe[vst->dfx].pts = pts*1000.0; - vst->vframe[vst->dfx].ready = 1; - vst->dfx = (vst->dfx + 1) & 3; - frames_count++; - }; - mutex_unlock(&vst->gpu_lock); - + return 0; }; + + frameFinished = 0; + if(dts == 0) + dts = pkt.pts; + + mutex_lock(&vst->gpu_lock); + + if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) + printf("video decoder error\n"); + + if(frameFinished) + { + vframe_t *vframe; + AVPicture *dst_pic; + + pts = av_frame_get_best_effort_timestamp(Frame); + pts *= av_q2d(video_time_base); + + vframe = vst->decoder_frame; + dst_pic = &vframe->picture; + + if(vframe->is_hw_pic == 0) + av_image_copy(dst_pic->data, dst_pic->linesize, + (const uint8_t**)Frame->data, + Frame->linesize, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); + else + va_create_planar(vst, vframe); + + vframe->pts = pts*1000.0; + vframe->pkt_pts = pkt.pts*av_q2d(video_time_base)*1000.0; + vframe->pkt_dts = dts*av_q2d(video_time_base)*1000.0; + vframe->ready = 1; + + + mutex_lock(&vst->output_lock); + + if(list_empty(&vst->output_list)) + list_add_tail(&vframe->list, &vst->output_list); + else + { + vframe_t *cur; + + cur = list_first_entry(&vst->output_list,vframe_t,list); + if(vframe->pkt_pts < cur->pkt_pts) + { + list_add_tail(&vframe->list, &vst->output_list); + } + else + { + list_for_each_entry_reverse(cur,&vst->output_list,list) + { + if(vframe->pkt_pts > cur->pkt_pts) + { + list_add(&vframe->list, &cur->list); + break; + }; + }; + }; + }; + mutex_unlock(&vst->output_lock); + + +// printf("decoded index: %d pts: %f pkt_pts %f pkt_dts %f\n", +// vst->dfx, vst->vframe[vst->dfx].pts, +// vst->vframe[vst->dfx].pkt_pts, vst->vframe[vst->dfx].pkt_dts); + + vst->decoder_frame = NULL; + frames_count++; + dts = 0; + }; + av_frame_unref(Frame); + mutex_unlock(&vst->gpu_lock); + av_free_packet(&pkt); return 1; @@ -357,8 +392,6 @@ int MainWindowProc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2) return 0; }; -#define VERSION_A 1 - void render_time(render_t *render) { progress_t *prg = main_render->win->panel.prg; @@ -367,8 +400,6 @@ void render_time(render_t *render) double ctime; /* milliseconds */ double fdelay; /* milliseconds */ -//again: - if(player_state == CLOSED) { render->win->win_command = WIN_CLOSED; @@ -390,51 +421,38 @@ void render_time(render_t *render) return; }; - -#ifdef VERSION_A - if(vst->vframe[vst->vfx].ready == 1 ) + mutex_lock(&vst->output_lock); + if(list_empty(&vst->output_list)) { + mutex_unlock(&vst->output_lock); + delay(1); + } + else + { + vframe_t *vframe; int sys_time; - ctime = get_master_clock(); - fdelay = (vst->vframe[vst->vfx].pts - ctime); + vframe = list_first_entry(&vst->output_list, vframe_t, list); + list_del(&vframe->list); + mutex_unlock(&vst->output_lock); -// printf("pts %f time %f delay %f\n", -// frames[vfx].pts, ctime, fdelay); + ctime = get_master_clock(); + fdelay = (vframe->pkt_pts - ctime); if(fdelay > 15.0) { delay((int)fdelay/10); - // return; }; -#if 0 - ctime = get_master_clock(); - fdelay = (vst->vframe[vst->vfx].pts - ctime); -// while(fdelay > 0) -// { -// yield(); -// ctime = get_master_clock(); -// fdelay = (frames[vfx].pts - ctime); -// } +// printf("output index: %d pts: %f pkt_pts %f pkt_dts %f\n", +// vframe->index,vframe->pts,vframe->pkt_pts,vframe->pkt_dts); -// sys_time = get_tick_count(); + main_render->draw(main_render, vframe); -// if(fdelay < 0) -// printf("systime %d pts %f time %f delay %f\n", -// sys_time*10, frames[vfx].pts, ctime, fdelay); - - printf("pts %f time %f delay %f\n", - vst->vframe[vst->vfx].pts, ctime, fdelay); - printf("video cache %d audio cache %d\n", q_video.size/1024, q_audio.size/1024); -#endif - - main_render->draw(main_render, &vst->vframe[vst->vfx].picture); if(main_render->win->win_state != FULLSCREEN) { - prg->current = vst->vframe[vst->vfx].pts*1000; -// printf("current %f\n", prg->current); - lvl->current = vst->vfx & 1 ? sound_level_1 : sound_level_0; + prg->current = vframe->pkt_pts * 1000; + lvl->current = vframe->index & 1 ? sound_level_1 : sound_level_0; send_message(&prg->ctrl, PRG_PROGRESS, 0, 0); @@ -443,69 +461,12 @@ void render_time(render_t *render) } frames_count--; - vst->vframe[vst->vfx].ready = 0; - vst->vfx = (vst->vfx + 1) & 3; + vframe->ready = 0; + + mutex_lock(&vst->input_lock); + list_add_tail(&vframe->list, &vst->input_list); + mutex_unlock(&vst->input_lock); } - else delay(1); - -#else - - if(vst->vframe[vfx].ready == 1 ) - { - ctime = get_master_clock(); - fdelay = (vst->vrame[vst->vfx].pts - ctime); - -// printf("pts %f time %f delay %f\n", -// frames[vfx].pts, ctime, fdelay); - - if(fdelay < 0.0 ) - { - int next_vfx; - fdelay = 0; - next_vfx = (vst->vfx+1) & 3; - if( vst->vrame[next_vfx].ready == 1 ) - { - if(vst->vrame[next_vfx].pts <= ctime) - { - vst->vrame[vst->vfx].ready = 0; // skip this frame - vst->vfx = (vst->vfx + 1) & 3; - } - else - { - if( (vst->vrame[next_vfx].pts - ctime) < - ( ctime - frames[vst->vfx].pts) ) - { - vst->vrame[vst->vfx].ready = 0; // skip this frame - vst->vfx = (vst->vfx + 1) & 3; - fdelay = (vst->vrame[next_vfx].pts - ctime); - } - } - }; - }; - - if(fdelay > 10.0) - { - int val = fdelay; - printf("pts %f time %f delay %d\n", - vst->vrame[vst->vfx].pts, ctime, val); - delay(val/10); - }; - - ctime = get_master_clock(); - fdelay = (vst->vrame[vst->vfx].pts - ctime); - - printf("pts %f time %f delay %f\n", - vst->vrame[vst->vfx].pts, ctime, fdelay); - - main_render->draw(main_render, &vst->vrame[vfx].picture); - main_render->win->panel.prg->current = vst->vrame[vfx].pts; -// send_message(&render->win->panel.prg->ctrl, MSG_PAINT, 0, 0); - vst->vrame[vst->vfx].ready = 0; - vst->vfx = (vst->vfx + 1) & 3; - } - else yield(); -#endif - } @@ -519,7 +480,7 @@ int video_thread(void *param) init_winlib(); MainWindow = create_window(movie_file,0, - 10,10,width,height+CAPTION_HEIGHT+PANEL_HEIGHT,MainWindowProc); + 10,10,vst->vCtx->width,vst->vCtx->height+CAPTION_HEIGHT+PANEL_HEIGHT,MainWindowProc); MainWindow->panel.prg->max = stream_duration; @@ -528,6 +489,7 @@ int video_thread(void *param) main_render = create_render(vst, MainWindow, HW_TEX_BLIT|HW_BIT_BLIT); if( main_render == NULL) { + mutex_unlock(&vst->decoder_lock); printf("Cannot create render\n\r"); return 0; }; @@ -537,6 +499,8 @@ int video_thread(void *param) render_draw_client(main_render); player_state = PLAY; + mutex_unlock(&vst->decoder_lock); + run_render(MainWindow, main_render); __sync_and_and_fetch(&threads_running,~VIDEO_THREAD); @@ -548,8 +512,8 @@ int video_thread(void *param) }; -void draw_hw_picture(render_t *render, AVPicture *picture); -void draw_sw_picture(render_t *render, AVPicture *picture); +void draw_hw_picture(render_t *render, vframe_t *vframe); +void draw_sw_picture(render_t *render, vframe_t *vframe); render_t *create_render(vst_t *vst, window_t *win, uint32_t flags) { @@ -783,8 +747,26 @@ void render_adjust_size(render_t *render, window_t *win) return; }; -void draw_hw_picture(render_t *render, AVPicture *picture) +static void render_hw_planar(render_t *render, vframe_t *vframe) { + vst_t *vst = render->vst; + planar_t *planar = vframe->planar; + + if(vframe->is_hw_pic != 0 && vframe->format != AV_PIX_FMT_NONE) + { + mutex_lock(&render->vst->gpu_lock); + + pxBlitPlanar(planar, render->rcvideo.l, + CAPTION_HEIGHT+render->rcvideo.t, + render->rcvideo.r, render->rcvideo.b,0,0); + mutex_unlock(&render->vst->gpu_lock); + + } +}; + +void draw_hw_picture(render_t *render, vframe_t *vframe) +{ + AVPicture *picture; int dst_width; int dst_height; bitmap_t *bitmap; @@ -794,6 +776,8 @@ void draw_hw_picture(render_t *render, AVPicture *picture) int linesize[4]; enum AVPixelFormat format; + vst_t *vst = render->vst; + if(render->win->win_state == MINIMIZED || render->win->win_state == ROLLED) return; @@ -809,11 +793,18 @@ void draw_hw_picture(render_t *render, AVPicture *picture) dst_height = render->rcvideo.b; }; - format = render->vst->hwdec == 0 ? render->ctx_format : AV_PIX_FMT_BGRA - cvt_ctx = sws_getCachedContext(cvt_ctx, - render->ctx_width, render->ctx_height, format, - dst_width, dst_height, AV_PIX_FMT_BGRA, - SWS_FAST_BILINEAR, NULL, NULL, NULL); + if(vst->hwdec) + { + render_hw_planar(render, vframe); + return; + }; + + picture = &vframe->picture; + + format = render->vst->hwdec == 0 ? render->ctx_format : AV_PIX_FMT_BGRA; + cvt_ctx = sws_getCachedContext(cvt_ctx, render->ctx_width, render->ctx_height, format, + dst_width, dst_height, AV_PIX_FMT_BGRA, + SWS_FAST_BILINEAR, NULL, NULL, NULL); if(cvt_ctx == NULL) { printf("Cannot initialize the conversion context!\n"); @@ -829,7 +820,6 @@ void draw_hw_picture(render_t *render, AVPicture *picture) return ; } -// printf("sws_getCachedContext\n"); data[0] = bitmap_data; data[1] = bitmap_data+1; data[2] = bitmap_data+2; @@ -874,8 +864,9 @@ void draw_hw_picture(render_t *render, AVPicture *picture) render->target&= 1; } -void draw_sw_picture(render_t *render, AVPicture *picture) +void draw_sw_picture(render_t *render, vframe_t *vframe) { + AVPicture *picture; uint8_t *bitmap_data; uint32_t bitmap_pitch; uint8_t *data[4]; @@ -885,6 +876,8 @@ void draw_sw_picture(render_t *render, AVPicture *picture) render->win->win_state == ROLLED) return; + picture = &vframe->picture; + cvt_ctx = sws_getCachedContext(cvt_ctx, render->ctx_width, render->ctx_height, render->ctx_format, @@ -937,9 +930,9 @@ void render_draw_client(render_t *render) if(player_state == PAUSE) { - if(vst->vframe[vst->vfx].ready == 1 ) - main_render->draw(main_render, &vst->vframe[vst->vfx].picture); - else +// if(vst->vframe[vst->vfx].ready == 1 ) +// main_render->draw(main_render, &vst->vframe[vst->vfx].picture); +// else draw_bar(0, y, render->win_width, render->rcvideo.b, 0); } diff --git a/contrib/media/fplay/winlib/link.h b/contrib/media/fplay/winlib/link.h index 8f72bb3411..3bb74dd20f 100644 --- a/contrib/media/fplay/winlib/link.h +++ b/contrib/media/fplay/winlib/link.h @@ -38,7 +38,7 @@ static inline void list_remove(link_t *link) link_initialize(link); } -static inline int list_empty(link_t *head) +static inline int llist_empty(link_t *head) { return head->next == head ? 1 : 0; } diff --git a/contrib/media/fplay/winlib/window.c b/contrib/media/fplay/winlib/window.c index 8fcb049e09..6dac48523c 100644 --- a/contrib/media/fplay/winlib/window.c +++ b/contrib/media/fplay/winlib/window.c @@ -35,6 +35,9 @@ static int need_update; void adjust_frame(window_t *win); +void blit_panel(panel_t *panel); +void update_panel_size(window_t *win); +void update_caption_size(window_t *win); //#include "timer.h" ctrl_t *win_get_child(window_t *win, int x, int y)