19. packet_queue_put
//这个函数很简单,就call 了packet_queue_put_private
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;
}
//将packet丢进packet queue中
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
MyAVPacketList *pkt1;
if (q->abort_request)
return -1;
//分配memory
pkt1 = av_malloc(sizeof(MyAVPacketList));
if (!pkt1)
return -1;
pkt1->pkt = *pkt;
pkt1->next = NULL;
if (pkt == &flush_pkt)
q->serial++; //如果是flush_pkt,需要将serial +1, 后面介绍过decoder会需要check这个值
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 */
//发一个signal给decoder thread,让decoder thread 脱离阻塞
SDL_CondSignal(q->cond);
return 0;
}
20.多线程decode
回到学习七的decoder_decode_frame,这个函数会调用 avcodec_decode_video2
发现有一篇blog https://blog.csdn.net/xietao_live_cn/article/details/6452030 讲解得比较清楚,可以参考
int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt)
{
...
if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
...
//多线程decoder 会走到ff_thread_decode_frame
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
&tmp);
else {
ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
&tmp);
...
}
...
}
int ff_thread_decode_frame(AVCodecContext *avctx,
AVFrame *picture, int *got_picture_ptr,
AVPacket *avpkt)
{
...
//将这个packet 提交给多线程处理
err = submit_packet(p, avpkt);
...
do {
p = &fctx->threads[finished++];
if (p->state != STATE_INPUT_READY) {
//为了和多线程同步
pthread_mutex_lock(&p->progress_mutex);
//等待多线程decoder 完成,会收到signal p->output_cond
while (p->state != STATE_INPUT_READY)
pthread_cond_wait(&p->output_cond, &p->progress_mutex);
pthread_mutex_unlock(&p->progress_mutex);
}
...
} while (!avpkt->size && !*got_picture_ptr && finished != fctx->next_finished);
...
}
static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
{
...
//给多线程发送signal p->input_cond,wake up decode thread
p->state = STATE_SETTING_UP;
pthread_cond_signal(&p->input_cond);
pthread_mutex_unlock(&p->mutex);
...
}