void ff_thread_flush(AVCodecContext *avctx) { FrameThreadContext *fctx = avctx->thread_opaque; int i; if (!avctx->thread_opaque) return; park_frame_worker_threads(fctx, avctx->thread_count); if (fctx->prev_thread) { if (fctx->prev_thread != &fctx->threads[0]) update_context_from_thread(fctx->threads[0].avctx, fctx->prev_thread->avctx, 0); if (avctx->codec->flush) avctx->codec->flush(fctx->threads[0].avctx); } fctx->next_decoding = fctx->next_finished = 0; fctx->delaying = 1; fctx->prev_thread = NULL; for (i = 0; i < avctx->thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; // Make sure decode flush calls with size=0 won't return old frames p->got_frame = 0; release_delayed_buffers(p); } }
static void frame_thread_free(AVCodecContext *avctx, int thread_count) { FrameThreadContext *fctx = avctx->thread_opaque; AVCodec *codec = avctx->codec; int i; park_frame_worker_threads(fctx, thread_count); if (fctx->prev_thread && fctx->prev_thread != fctx->threads) update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0); fctx->die = 1; for (i = 0; i < thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; pthread_mutex_lock(&p->mutex); pthread_cond_signal(&p->input_cond); pthread_mutex_unlock(&p->mutex); if (p->thread_init) pthread_join(p->thread, NULL); p->thread_init=0; if (codec->close) codec->close(p->avctx); avctx->codec = NULL; release_delayed_buffers(p); } for (i = 0; i < thread_count; i++) { PerThreadContext *p = &fctx->threads[i]; avcodec_default_free_buffers(p->avctx); pthread_mutex_destroy(&p->mutex); pthread_mutex_destroy(&p->progress_mutex); pthread_cond_destroy(&p->input_cond); pthread_cond_destroy(&p->progress_cond); pthread_cond_destroy(&p->output_cond); av_freep(&p->avpkt.data); if (i) { av_freep(&p->avctx->priv_data); av_freep(&p->avctx->internal); av_freep(&p->avctx->slice_offset); } av_freep(&p->avctx); } av_freep(&fctx->threads); pthread_mutex_destroy(&fctx->buffer_mutex); av_freep(&avctx->thread_opaque); }
void ff_thread_flush(AVCodecContext *avctx) { FrameThreadContext *fctx = avctx->thread_opaque; if (!avctx->thread_opaque) return; park_frame_worker_threads(fctx, avctx->thread_count); if (fctx->prev_thread) { if (fctx->prev_thread != &fctx->threads[0]) update_context_from_thread(fctx->threads[0].avctx, fctx->prev_thread->avctx, 0); if (avctx->codec->flush) avctx->codec->flush(fctx->threads[0].avctx); } fctx->next_decoding = fctx->next_finished = 0; fctx->delaying = 1; fctx->prev_thread = NULL; }
static int frame_thread_init(AVCodecContext *avctx) { int thread_count = avctx->thread_count; AVCodec *codec = avctx->codec; AVCodecContext *src = avctx; FrameThreadContext *fctx; int i, err = 0; if (!thread_count) { int nb_cpus = get_logical_cpus(avctx); if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv) nb_cpus = 1; // use number of cores + 1 as thread count if there is more than one if (nb_cpus > 1) thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); else thread_count = avctx->thread_count = 1; } if (thread_count <= 1) { avctx->active_thread_type = 0; return 0; } avctx->thread_opaque = fctx = av_mallocz(sizeof(FrameThreadContext)); fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count); pthread_mutex_init(&fctx->buffer_mutex, NULL); fctx->delaying = 1; for (i = 0; i < thread_count; i++) { AVCodecContext *copy = av_malloc(sizeof(AVCodecContext)); PerThreadContext *p = &fctx->threads[i]; pthread_mutex_init(&p->mutex, NULL); pthread_mutex_init(&p->progress_mutex, NULL); pthread_cond_init(&p->input_cond, NULL); pthread_cond_init(&p->progress_cond, NULL); pthread_cond_init(&p->output_cond, NULL); p->parent = fctx; p->avctx = copy; if (!copy) { err = AVERROR(ENOMEM); goto error; } *copy = *src; copy->thread_opaque = p; copy->pkt = &p->avpkt; if (!i) { src = copy; if (codec->init) err = codec->init(copy); update_context_from_thread(avctx, copy, 1); } else { copy->priv_data = av_malloc(codec->priv_data_size); if (!copy->priv_data) { err = AVERROR(ENOMEM); goto error; } memcpy(copy->priv_data, src->priv_data, codec->priv_data_size); copy->internal = av_malloc(sizeof(AVCodecInternal)); if (!copy->internal) { err = AVERROR(ENOMEM); goto error; } *copy->internal = *src->internal; copy->internal->is_copy = 1; if (codec->init_thread_copy) err = codec->init_thread_copy(copy); } if (err) goto error; err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); p->thread_init= !err; if(!p->thread_init) goto error; } return 0; error: frame_thread_free(avctx, i+1); return err; }
int ff_thread_decode_frame(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt) { FrameThreadContext *fctx = avctx->thread_opaque; int finished = fctx->next_finished; PerThreadContext *p; int err; /* * Submit a packet to the next decoding thread. */ p = &fctx->threads[fctx->next_decoding]; err = update_context_from_user(p->avctx, 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). */ do { p = &fctx->threads[finished++]; if (p->state != STATE_INPUT_READY) { pthread_mutex_lock(&p->progress_mutex); while (p->state != STATE_INPUT_READY) pthread_cond_wait(&p->output_cond, &p->progress_mutex); pthread_mutex_unlock(&p->progress_mutex); } *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; }
static int submit_packet(PerThreadContext *p, AVPacket *avpkt) { FrameThreadContext *fctx = p->parent; PerThreadContext *prev_thread = fctx->prev_thread; AVCodec *codec = p->avctx->codec; uint8_t *buf = p->avpkt.data; if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0; pthread_mutex_lock(&p->mutex); release_delayed_buffers(p); if (prev_thread) { int err; if (prev_thread->state == STATE_SETTING_UP) { pthread_mutex_lock(&prev_thread->progress_mutex); while (prev_thread->state == STATE_SETTING_UP) pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex); pthread_mutex_unlock(&prev_thread->progress_mutex); } err = update_context_from_thread(p->avctx, prev_thread->avctx, 0); if (err) { pthread_mutex_unlock(&p->mutex); return err; } } av_fast_malloc(&buf, &p->allocated_buf_size, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE); p->avpkt = *avpkt; p->avpkt.data = buf; memcpy(buf, avpkt->data, avpkt->size); memset(buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); p->state = STATE_SETTING_UP; pthread_cond_signal(&p->input_cond); pthread_mutex_unlock(&p->mutex); /* * If the client doesn't have a thread-safe get_buffer(), * then decoding threads call back to the main thread, * and it calls back to the client here. */ if (!p->avctx->thread_safe_callbacks && p->avctx->get_buffer != avcodec_default_get_buffer) { while (p->state != STATE_SETUP_FINISHED && p->state != STATE_INPUT_READY) { pthread_mutex_lock(&p->progress_mutex); while (p->state == STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); if (p->state == STATE_GET_BUFFER) { p->result = p->avctx->get_buffer(p->avctx, p->requested_frame); p->state = STATE_SETTING_UP; pthread_cond_signal(&p->progress_cond); } pthread_mutex_unlock(&p->progress_mutex); } } fctx->prev_thread = p; fctx->next_decoding++; return 0; }
static int submit_packet(PerThreadContext *p, AVPacket *avpkt) { FrameThreadContext *fctx = p->parent; PerThreadContext *prev_thread = fctx->prev_thread; const AVCodec *codec = p->avctx->codec; if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0; pthread_mutex_lock(&p->mutex); release_delayed_buffers(p); if (prev_thread) { int err; if (prev_thread->state == STATE_SETTING_UP) { pthread_mutex_lock(&prev_thread->progress_mutex); while (prev_thread->state == STATE_SETTING_UP) pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex); pthread_mutex_unlock(&prev_thread->progress_mutex); } err = update_context_from_thread(p->avctx, prev_thread->avctx, 0); if (err) { pthread_mutex_unlock(&p->mutex); return err; } } av_buffer_unref(&p->avpkt.buf); p->avpkt = *avpkt; if (avpkt->buf) p->avpkt.buf = av_buffer_ref(avpkt->buf); else { av_fast_malloc(&p->buf, &p->allocated_buf_size, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE); if (!p->buf) { pthread_mutex_unlock(&p->mutex); return AVERROR(ENOMEM); } p->avpkt.data = p->buf; memcpy(p->buf, avpkt->data, avpkt->size); memset(p->buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); } p->state = STATE_SETTING_UP; pthread_cond_signal(&p->input_cond); pthread_mutex_unlock(&p->mutex); /* * If the client doesn't have a thread-safe get_buffer(), * then decoding threads call back to the main thread, * and it calls back to the client here. */ FF_DISABLE_DEPRECATION_WARNINGS if (!p->avctx->thread_safe_callbacks && ( p->avctx->get_format != avcodec_default_get_format || #if FF_API_GET_BUFFER p->avctx->get_buffer || #endif p->avctx->get_buffer2 != avcodec_default_get_buffer2)) { FF_ENABLE_DEPRECATION_WARNINGS while (p->state != STATE_SETUP_FINISHED && p->state != STATE_INPUT_READY) { int call_done = 1; pthread_mutex_lock(&p->progress_mutex); while (p->state == STATE_SETTING_UP) pthread_cond_wait(&p->progress_cond, &p->progress_mutex); switch (p->state) { case STATE_GET_BUFFER: p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags); break; case STATE_GET_FORMAT: p->result_format = p->avctx->get_format(p->avctx, p->available_formats); break; default: call_done = 0; break; } if (call_done) { p->state = STATE_SETTING_UP; pthread_cond_signal(&p->progress_cond); } pthread_mutex_unlock(&p->progress_mutex); } }