//帧级解码函数,在avcodec_open2的时候,就会判断片还是帧解码,分析见下一篇
int ff_thread_decode_frame(AVCodecContext *avctx,
AVFrame *picture, int *got_picture_ptr,AVPacket *avpkt)
{
FrameThreadContext *fctx = avctx->thread_opaque; //thread_opaque见注释1
int finished = fctx->next_finished; //从返回结果输出的下一个内容
PerThreadContext *p; //查看注释2
int err;
/*
* Submit a packet to the next decoding thread.
*提交数据包发送到下一个解码线程
p = &fctx->threads[fctx->next_decoding];
err = update_context_from_user(p->avctx, avctx); //将用户提交的avctx复制到p->avctx里面
if (err) return err;
err = submit_packet(p, avpkt);
if (err) return err;
/*
* If we're still receiving the initial packets, don't return a frame.
*如果我们仍然接收的初步数据包,不返回帧
*/
if (fctx->delaying) {
if (fctx->next_decoding >= (avctx->thread_count-1)) fctx->delaying = 0;
*got_picture_ptr=0;
if (avpkt->size)
return avpkt->size;
}
/*
* Return the next available frame from the oldest thread.//返回下一个可用帧从最早的线程
* If we're at the end of the stream, then we have to skip threads that
* didn't output a frame, because we don't want to accidentally signal
* EOF (avpkt->size == 0 && *got_picture_ptr == 0).//因为我们不希望发生意外信号EOF,所以在流的最后,我们必须跳过线程,而不输出帧
* /
do {
p = &fctx->threads[finished++];
if (p->state != STATE_INPUT_READY) {
pthread_mutex_lock(&p->progress_mutex);
while (p->state != STATE_INPUT_READY) //如果数据的状态不是STATE_INPUT_READY,线程进行等待,直到线程pthread_cond_signal(&p->progress_cond) ;
pthread_cond_wait(&p->output_cond, &p->progress_mutex);
pthread_mutex_unlock(&p->progress_mutex);
}
av_frame_move_ref(picture, &p->frame);
*got_picture_ptr = p->got_frame;
picture->pkt_dts = p->avpkt.dts;
/*
* A later call with avkpt->size == 0 may loop over all threads,
* including this one, searching for a frame to return before being
* stopped by the "finished != fctx->next_finished" condition.
* Make sure we don't mistakenly return the same frame again.
*/
p->got_frame = 0;
if (finished >= avctx->thread_count) finished = 0;
} while (!avpkt->size && !*got_picture_ptr && finished != fctx->next_finished);
update_context_from_thread(avctx, p->avctx, 1);
if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0;
fctx->next_finished = finished;
/* return the size of the consumed packet if no error occurred */
return (p->result >= 0) ? avpkt->size : p->result;
}
注释:
1.
/**
* thread opaque
* Can be used by execute() to store some per AVCodecContext stuff.
//能够使用execute()函数来存储每个AVCodecContext数据
* - encoding: set by execute()
* - decoding: set by execute()
*/
void *thread_opaque;
2.
/**
* Context used by codec threads and stored in their AVCodecContext thread_opaque.
*上下文所使用的编解码器线程和存储在他们的AVCodecContext thread_opaque
*/
typedef struct PerThreadContext {
struct FrameThreadContext *parent;
pthread_t thread;
int thread_init;
pthread_cond_t input_cond; ///< Used to wait for a new packet from the main thread.从主线程等待一个新的数据包。
pthread_cond_t progress_cond; ///< Used by child threads to wait for progress to change.
pthread_cond_t output_cond; ///< Used by the main thread to wait for frames to finish.用于由主线程等待帧来完成
pthread_mutex_t mutex; ///< Mutex used to protect the contents of the PerThreadContext.
pthread_mutex_t progress_mutex; ///< Mutex used to protect frame progress values and progress_cond.
AVCodecContext *avctx; ///< Context used to decode packets passed to this thread.
AVPacket avpkt; ///< Input packet (for decoding) or output (for encoding).
uint8_t *buf; ///< backup storage for packet data when the input packet is not refcounted
int allocated_buf_size; ///< Size allocated for buf
AVFrame frame; ///< Output frame (for decoding) or input (for encoding).
int got_frame; ///< The output of got_picture_ptr from the last avcodec_decode_video() call.
int result; ///< The result of the last codec decode/encode() call.
enum { //这个可以看之前文章中提到的帧级解码状态图
STATE_INPUT_READY, ///< Set when the thread is awaiting a packet.
STATE_SETTING_UP, ///< Set before the codec has called ff_thread_finish_setup().
STATE_GET_BUFFER, /**<
* Set when the codec calls get_buffer().
* State is returned to STATE_SETTING_UP afterwards.
*/
STATE_SETUP_FINISHED ///< Set after the codec has called ff_thread_finish_setup().
} state;
/**
* Array of frames passed to ff_thread_release_buffer().
* Frames are released after all threads referencing them are finished.
*/
AVFrame *released_buffers;
int num_released_buffers;
int released_buffers_allocated;
AVFrame *requested_frame; ///< AVFrame the codec passed to get_buffer()
int requested_flags; ///< flags passed to get_buffer() for requested_frame
} PerThreadContext;