ffplay.c数据结构分析
2016-08-02 11:20
127 查看
最近在做流媒体播放器的优化,参考了ffplay.c的代码,主要对存储和流程上做下解剖。
数据存储
15M的QUEUE
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
typedef struct MyAVPacketList {
AVPacket pkt;
struct MyAVPacketList *next;
int serial;
} MyAVPacketList;
typedef struct PacketQueue {
MyAVPacketList *first_pkt, *last_pkt;
int nb_packets;
int size;
int abort_request;
int serial;
SDL_mutex *mutex;
SDL_cond *cond;
} PacketQueue;
typedef struct FrameQueue {
Frame queue[FRAME_QUEUE_SIZE];
int rindex;
int windex;
int size;
int max_size;
int keep_last;
int rindex_shown;
SDL_mutex *mutex;
SDL_cond *cond;
PacketQueue *pktq;
} FrameQueue;
解码播放流程:
读线程:
is->read_tid = SDL_CreateThread(read_thread, is);/* this thread gets the stream from the disk or the network */
主要作用是读取一帧编码后的数据,然后入队
ret = av_read_frame(ic, pkt);
packet_queue_put(&is->videoq, pkt);
入队代码:
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
MyAVPacketList *pkt1;
if (q->abort_request)
return -1;
pkt1 = av_malloc(sizeof(MyAVPacketList));
if (!pkt1)
return -1;
pkt1->pkt = *pkt;
pkt1->next = NULL;
if (pkt == &flush_pkt)
q->serial++;
pkt1->serial = q->serial;
if (!q->last_pkt)
q->first_pkt = pkt1;
else
q->last_pkt->next = pkt1;
q->last_pkt = pkt1;
q->nb_packets++;
q->size += pkt1->pkt.size + sizeof(*pkt1);
/* XXX: should duplicate packet data in DV case */
SDL_CondSignal(q->cond);
return 0;
}
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
int ret;
/* duplicate the packet */
if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
return -1;
SDL_LockMutex(q->mutex);
ret = packet_queue_put_private(q, pkt);
SDL_UnlockMutex(q->mutex);
if (pkt != &flush_pkt && ret < 0)
av_free_packet(pkt);
return ret;
}
解码线程:
decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
decoder_start(&is->auddec, audio_thread, is);
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
decoder_start(&is->viddec, video_thread, is);
video_thread的流程:
get_video_frame 然后去刷新界面
for (;;) {
ret = get_video_frame(is, frame);
}
get_video_frame是解码后得到一帧:
if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
decoder_decode_frame是得到从packet_queue_get中得到一个packet并扔给解码器解码:
if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
return -1;
packet_queue_get是等待信号量直到得到一个pkt:
分析完了。
数据存储
15M的QUEUE
#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
typedef struct MyAVPacketList {
AVPacket pkt;
struct MyAVPacketList *next;
int serial;
} MyAVPacketList;
typedef struct PacketQueue {
MyAVPacketList *first_pkt, *last_pkt;
int nb_packets;
int size;
int abort_request;
int serial;
SDL_mutex *mutex;
SDL_cond *cond;
} PacketQueue;
typedef struct FrameQueue {
Frame queue[FRAME_QUEUE_SIZE];
int rindex;
int windex;
int size;
int max_size;
int keep_last;
int rindex_shown;
SDL_mutex *mutex;
SDL_cond *cond;
PacketQueue *pktq;
} FrameQueue;
解码播放流程:
读线程:
is->read_tid = SDL_CreateThread(read_thread, is);/* this thread gets the stream from the disk or the network */
主要作用是读取一帧编码后的数据,然后入队
ret = av_read_frame(ic, pkt);
packet_queue_put(&is->videoq, pkt);
入队代码:
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
MyAVPacketList *pkt1;
if (q->abort_request)
return -1;
pkt1 = av_malloc(sizeof(MyAVPacketList));
if (!pkt1)
return -1;
pkt1->pkt = *pkt;
pkt1->next = NULL;
if (pkt == &flush_pkt)
q->serial++;
pkt1->serial = q->serial;
if (!q->last_pkt)
q->first_pkt = pkt1;
else
q->last_pkt->next = pkt1;
q->last_pkt = pkt1;
q->nb_packets++;
q->size += pkt1->pkt.size + sizeof(*pkt1);
/* XXX: should duplicate packet data in DV case */
SDL_CondSignal(q->cond);
return 0;
}
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
int ret;
/* duplicate the packet */
if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
return -1;
SDL_LockMutex(q->mutex);
ret = packet_queue_put_private(q, pkt);
SDL_UnlockMutex(q->mutex);
if (pkt != &flush_pkt && ret < 0)
av_free_packet(pkt);
return ret;
}
解码线程:
decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
decoder_start(&is->auddec, audio_thread, is);
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
decoder_start(&is->viddec, video_thread, is);
video_thread的流程:
get_video_frame 然后去刷新界面
for (;;) {
ret = get_video_frame(is, frame);
}
get_video_frame是解码后得到一帧:
if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
decoder_decode_frame是得到从packet_queue_get中得到一个packet并扔给解码器解码:
if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
return -1;
packet_queue_get是等待信号量直到得到一个pkt:
/* return < 0 if aborted, 0 if no packet and > 0 if packet. */ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial) { MyAVPacketList *pkt1; int ret; SDL_LockMutex(q->mutex); for (;;) { if (q->abort_request) { ret = -1; break; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size + sizeof(*pkt1); *pkt = pkt1->pkt; if (serial) *serial = pkt1->serial; av_free(pkt1); ret = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; }
分析完了。
相关文章推荐
- 排序
- 数据结构实验之链表九:双向链表
- 数据结构实验之七:出栈序列判定 (sdut oj3334)
- bzoj 1500 NOI2005 维修数列 [Splay]
- Codevs 1743 反转卡片 [Splay]
- 数据结构-队列
- 回文串判定
- 数据结构实验之链表六:有序链表的建立(C语言)
- 队列
- 数据结构实验之链表九:双向链表
- 数据结构实验之图论二:基于邻接表的广度优先搜索遍历
- 数据结构实验之栈八:栈的基本操作
- 数据结构第二天
- 数据结构实验之栈七:出栈序列判定
- 数据结构1_160801
- 数据结构实验之队列一:排队买饭
- 数据结构----划分树
- 数据结构
- 数据结构学习之用Java实现AVL树
- 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历