您的位置:首页 > 理论基础 > 数据结构算法

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:
/* 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;
}


分析完了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: