/contrib/media/fplay/audio.c |
---|
417,4 → 417,3 |
return -1; |
}; |
/contrib/media/fplay/fplay.c |
---|
26,9 → 26,6 |
uint32_t win_width, win_height; |
AVFrame *pFrame; |
int have_sound = 0; |
uint8_t *decoder_buffer; |
147,6 → 144,15 |
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 |
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,12 → 226,11 |
if(!init_video(&vst)) |
return 0; |
mutex_lock_timeout(&vst.decoder_lock, 3000); |
decoder(&vst); |
// Free the YUV frame |
av_free(pFrame); |
//__asm__ __volatile__("int3"); |
while( threads_running & |
241,7 → 242,7 |
mutex_destroy(&vst.q_video.lock); |
mutex_destroy(&vst.q_audio.lock); |
mutex_destroy(&vst.decoder_lock); |
return 0; |
} |
334,8 → 335,7 |
} |
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; |
/contrib/media/fplay/fplay.h |
---|
1,6 → 1,7 |
#include <libsync.h> |
#include "pixlib3.h" |
#include <pixlib3.h> |
#include "list.h" |
#define BLACK_MAGIC_SOUND |
#define BLACK_MAGIC_VIDEO |
18,10 → 19,15 |
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 |
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 |
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 |
::"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(); |
/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 |
/contrib/media/fplay/vaapi.c |
---|
17,7 → 17,7 |
{ |
enum AVCodecID av_codec; |
int ff_profile; |
uint64_t va_profile; |
VAProfile va_profile; |
}; |
39,7 → 39,7 |
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 |
{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 |
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 |
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 |
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 |
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 |
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 |
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 |
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,9 → 443,6 |
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); |
} |
463,8 → 449,10 |
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; |
struct av_surface *avsurface; |
493,20 → 481,16 |
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,11 → 504,14 |
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 ) |
{ |
531,9 → 518,11 |
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; |
540,87 → 529,129 |
} |
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) |
/* |
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()")) |
{ |
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()")) |
{ |
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(); |
} |
/contrib/media/fplay/video.c |
---|
28,35 → 28,38 |
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 |
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(); |
frameFinished = 0; |
if(dts == 0) |
dts = pkt.pts; |
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; |
mutex_lock(&vst->gpu_lock); |
if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) |
printf("video decoder error\n"); |
pts *= av_q2d(video_time_base)*1000.0; |
*/ |
if( 1 /*pts > current_clock*/) |
if(frameFinished) |
{ |
frameFinished = 0; |
vframe_t *vframe; |
AVPicture *dst_pic; |
vst->vCtx->reordered_opaque = pkt.pts; |
pts = av_frame_get_best_effort_timestamp(Frame); |
pts *= av_q2d(video_time_base); |
mutex_lock(&vst->gpu_lock); |
vframe = vst->decoder_frame; |
dst_pic = &vframe->picture; |
if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) |
printf("video decoder error\n"); |
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); |
if(frameFinished) |
{ |
AVPicture *dst_pic; |
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; |
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); |
mutex_lock(&vst->output_lock); |
dst_pic = &vst->vframe[vst->dfx].picture; |
if(list_empty(&vst->output_list)) |
list_add_tail(&vframe->list, &vst->output_list); |
else |
{ |
vframe_t *cur; |
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); |
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 |
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++; |
{ |
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->gpu_lock); |
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 |
return 0; |
}; |
#define VERSION_A 1 |
void render_time(render_t *render) |
{ |
progress_t *prg = main_render->win->panel.prg; |
367,8 → 400,6 |
double ctime; /* milliseconds */ |
double fdelay; /* milliseconds */ |
//again: |
if(player_state == CLOSED) |
{ |
render->win->win_command = WIN_CLOSED; |
390,51 → 421,38 |
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; |
vframe = list_first_entry(&vst->output_list, vframe_t, list); |
list_del(&vframe->list); |
mutex_unlock(&vst->output_lock); |
ctime = get_master_clock(); |
fdelay = (vst->vframe[vst->vfx].pts - ctime); |
fdelay = (vframe->pkt_pts - ctime); |
// printf("pts %f time %f delay %f\n", |
// frames[vfx].pts, ctime, fdelay); |
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 |
} |
frames_count--; |
vst->vframe[vst->vfx].ready = 0; |
vst->vfx = (vst->vfx + 1) & 3; |
} |
else delay(1); |
vframe->ready = 0; |
#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; |
mutex_lock(&vst->input_lock); |
list_add_tail(&vframe->list, &vst->input_list); |
mutex_unlock(&vst->input_lock); |
} |
else yield(); |
#endif |
} |
519,7 → 480,7 |
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 |
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 |
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 |
}; |
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 |
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 |
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 |
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 |
return ; |
} |
// printf("sws_getCachedContext\n"); |
data[0] = bitmap_data; |
data[1] = bitmap_data+1; |
data[2] = bitmap_data+2; |
874,8 → 864,9 |
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 |
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 |
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); |
} |
/contrib/media/fplay/winlib/link.h |
---|
38,7 → 38,7 |
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; |
} |
/contrib/media/fplay/winlib/window.c |
---|
35,6 → 35,9 |
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) |