On Sun, 3 Mar 2013 17:26:53 +0100, Janne Grunau <[email protected]> wrote:
> On 2013-02-13 19:50:38 +0100, Anton Khirnov wrote:
> > ---
> > doc/multithreading.txt | 5 ++
> > libavcodec/internal.h | 15 +++++
> > libavcodec/pthread.c | 169
> > ++++++++++++++++++++++++------------------------
> > libavcodec/thread.h | 20 ++++--
> > libavcodec/utils.c | 19 ++++++
> > 5 files changed, 139 insertions(+), 89 deletions(-)
> >
> > diff --git a/doc/multithreading.txt b/doc/multithreading.txt
> > index b72bc16..9b27b10 100644
> > --- a/doc/multithreading.txt
> > +++ b/doc/multithreading.txt
> > @@ -57,6 +57,11 @@ which re-allocates them for other threads.
> > Add CODEC_CAP_FRAME_THREADS to the codec capabilities. There will be very
> > little
> > speed gain at this point but it should work.
> >
> > +If there are inter-frame dependencies, so the codec calls
> > +ff_thread_report/await_progress(), set AVCodecInternal.allocate_progress.
> > The
> > +frames must then be freed with ff_thread_release_buffer().
> > +Otherwise leave it at zero and decode directly into the user-supplied
> > frames.
> > +
> > Call ff_thread_report_progress() after some part of the current picture
> > has decoded.
> > A good place to put this is where draw_horiz_band() is called - add this
> > if it isn't
> > called anywhere, as it's useful too and the implementation is trivial when
> > you're
> > diff --git a/libavcodec/internal.h b/libavcodec/internal.h
> > index 8e64640..594bd1e 100644
> > --- a/libavcodec/internal.h
> > +++ b/libavcodec/internal.h
> > @@ -61,6 +61,21 @@ typedef struct AVCodecInternal {
> > */
> > int is_copy;
> >
> > + /**
> > + * Whether to allocate progress for frame threading.
> > + *
> > + * The codec must set it to 1 if it uses
> > ff_thread_await/report_progress(),
> > + * then progress will be allocated in ff_thread_get_buffer(). The
> > frames
> > + * then MUST be freed with ff_thread_release_buffer().
> > + *
> > + * If the codec does not need to call the progress functions (there
> > are no
> > + * dependencies between the frames), it should leave this at 0. Then
> > it can
> > + * decode straight to the user-provided frames (which the user will
> > then
> > + * free with av_frame_unref()), there is no need to call
> > + * ff_thread_release_buffer().
> > + */
> > + int allocate_progress;
> > +
> > #if FF_API_OLD_DECODE_AUDIO
> > /**
> > * Internal sample count used by avcodec_encode_audio() to fabricate
> > pts.
> > diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c
> > index 82df03c..c2be1a4 100644
> > --- a/libavcodec/pthread.c
> > +++ b/libavcodec/pthread.c
> > @@ -52,6 +52,7 @@
> > #include "avcodec.h"
> > #include "internal.h"
> > #include "thread.h"
> > +#include "libavutil/avassert.h"
> > #include "libavutil/common.h"
> >
> > #if HAVE_PTHREADS
> > @@ -80,9 +81,6 @@ typedef struct ThreadContext {
> > int done;
> > } ThreadContext;
> >
> > -/// Max number of frame buffers that can be allocated when using frame
> > threads.
> > -#define MAX_BUFFERS (32+1)
> > -
> > /**
> > * Context used by codec threads and stored in their AVCodecContext
> > thread_opaque.
> > */
> > @@ -122,16 +120,12 @@ typedef struct PerThreadContext {
> > * Array of frames passed to ff_thread_release_buffer().
> > * Frames are released after all threads referencing them are finished.
> > */
> > - AVFrame released_buffers[MAX_BUFFERS];
> > - int num_released_buffers;
> > -
> > - /**
> > - * Array of progress values used by ff_thread_get_buffer().
> > - */
> > - int progress[MAX_BUFFERS][2];
> > - uint8_t progress_used[MAX_BUFFERS];
> > + 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;
> >
> > /**
> > @@ -459,8 +453,11 @@ static int update_context_from_user(AVCodecContext
> > *dst, AVCodecContext *src)
> > dst->flags = src->flags;
> >
> > dst->draw_horiz_band= src->draw_horiz_band;
> > + dst->get_buffer2 = src->get_buffer2;
> > +#if FF_API_GET_BUFFER
> > dst->get_buffer = src->get_buffer;
> > dst->release_buffer = src->release_buffer;
> > +#endif
> >
> > dst->opaque = src->opaque;
> > dst->debug = src->debug;
> > @@ -492,28 +489,21 @@ static int update_context_from_user(AVCodecContext
> > *dst, AVCodecContext *src)
> > #undef copy_fields
> > }
> >
> > -static void free_progress(AVFrame *f)
> > -{
> > - PerThreadContext *p = f->owner->thread_opaque;
> > - int *progress = f->thread_opaque;
> > -
> > - p->progress_used[(progress - p->progress[0]) / 2] = 0;
> > -}
> > -
> > /// Releases the buffers that this decoding thread was the last user of.
> > static void release_delayed_buffers(PerThreadContext *p)
> > {
> > FrameThreadContext *fctx = p->parent;
> > + AVFrame *f;
> >
> > while (p->num_released_buffers > 0) {
> > - AVFrame *f;
> > -
>
> unnecessary change, I won't mind though
>
Undid locally.
This was unintentional/related to some previous versions of this commit.
> > pthread_mutex_lock(&fctx->buffer_mutex);
> > +
> > + // fix extended data in case the caller screwed it up
> > + av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO);
> > f = &p->released_buffers[--p->num_released_buffers];
> > - free_progress(f);
> > - f->thread_opaque = NULL;
> > + f->extended_data = f->data;
> > + av_frame_unref(f);
> >
> > - f->owner->release_buffer(f->owner, f);
> > pthread_mutex_unlock(&fctx->buffer_mutex);
> > }
> > }
> > @@ -567,15 +557,18 @@ static int submit_packet(PerThreadContext *p,
> > AVPacket *avpkt)
> > * and it calls back to the client here.
> > */
> >
> > - if (!p->avctx->thread_safe_callbacks &&
> > - p->avctx->get_buffer != avcodec_default_get_buffer) {
> > + if (!p->avctx->thread_safe_callbacks && (
> > +#if FF_API_GET_BUFFER
> > + p->avctx->get_buffer ||
> > +#endif
> > + p->avctx->get_buffer2 != avcodec_default_get_buffer2)) {
> > 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 = ff_get_buffer(p->avctx, p->requested_frame);
> > + p->result = ff_get_buffer(p->avctx, p->requested_frame,
> > p->requested_flags);
> > p->state = STATE_SETTING_UP;
> > pthread_cond_signal(&p->progress_cond);
> > }
> > @@ -637,7 +630,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
> > pthread_mutex_unlock(&p->progress_mutex);
> > }
> >
> > - *picture = p->frame;
> > + av_frame_move_ref(picture, &p->frame);
> > *got_picture_ptr = p->got_frame;
> > picture->pkt_dts = p->avpkt.dts;
> >
> > @@ -662,10 +655,10 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
> > return (p->result >= 0) ? avpkt->size : p->result;
> > }
> >
> > -void ff_thread_report_progress(AVFrame *f, int n, int field)
> > +void ff_thread_report_progress(ThreadFrame *f, int n, int field)
> > {
> > PerThreadContext *p;
> > - int *progress = f->thread_opaque;
> > + int *progress = f->progress ? (int*)f->progress->data : NULL;
>
> the cast looks unecessary, please omit if that doesn't adds a warning.
> same for all following handling of progress
It is necessary, AVBufferRef.data is uint8_t* so it needs and explicit cast.
>
> > if (!progress || progress[field] >= n) return;
> >
> > @@ -680,10 +673,10 @@ void ff_thread_report_progress(AVFrame *f, int n, int
> > field)
> > pthread_mutex_unlock(&p->progress_mutex);
> > }
> >
> > -void ff_thread_await_progress(AVFrame *f, int n, int field)
> > +void ff_thread_await_progress(ThreadFrame *f, int n, int field)
> > {
> > PerThreadContext *p;
> > - int *progress = f->thread_opaque;
> > + int *progress = f->progress ? (int*)f->progress->data : NULL;
> >
> > if (!progress || progress[field] >= n) return;
> >
> > @@ -730,7 +723,7 @@ static void frame_thread_free(AVCodecContext *avctx,
> > int thread_count)
> > {
> > FrameThreadContext *fctx = avctx->thread_opaque;
> > const AVCodec *codec = avctx->codec;
> > - int i;
> > + int i, j;
>
> unused variable j
Removed locally.
--
Anton Khirnov
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel