Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/ffmpeg.c b/ffmpeg.c
- index e0463a9..6f400cc 100644
- --- a/ffmpeg.c
- +++ b/ffmpeg.c
- @@ -768,11 +768,6 @@ static int read_ffserver_streams(AVFormatContext *s, const char *filename)
- choose_pixel_fmt(st, codec);
- }
- - if(!st->codec->thread_count)
- - st->codec->thread_count = 1;
- - if(st->codec->thread_count>1)
- - avcodec_thread_init(st->codec, st->codec->thread_count);
- -
- if(st->codec->flags & CODEC_FLAG_BITEXACT)
- nopts = 1;
- }
- @@ -3433,7 +3428,7 @@ static void new_video_stream(AVFormatContext *oc, int file_idx)
- bitstream_filters[file_idx][oc->nb_streams - 1]= video_bitstream_filters;
- video_bitstream_filters= NULL;
- - avcodec_thread_init(st->codec, thread_count);
- + st->codec->thread_count= thread_count;
- video_enc = st->codec;
- @@ -3578,7 +3573,7 @@ static void new_audio_stream(AVFormatContext *oc, int file_idx)
- bitstream_filters[file_idx][oc->nb_streams - 1]= audio_bitstream_filters;
- audio_bitstream_filters= NULL;
- - avcodec_thread_init(st->codec, thread_count);
- + st->codec->thread_count= thread_count;
- audio_enc = st->codec;
- audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
- diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
- index 4bddbaa..c99e63a 100644
- --- a/libavcodec/avcodec.h
- +++ b/libavcodec/avcodec.h
- @@ -31,7 +31,7 @@
- #include "libavutil/cpu.h"
- #define LIBAVCODEC_VERSION_MAJOR 52
- -#define LIBAVCODEC_VERSION_MINOR 92
- +#define LIBAVCODEC_VERSION_MINOR 93
- #define LIBAVCODEC_VERSION_MICRO 0
- #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
- @@ -707,7 +707,10 @@ typedef struct RcOverride{
- * Codec should fill in channel configuration and samplerate instead of container
- */
- #define CODEC_CAP_CHANNEL_CONF 0x0400
- -
- +/**
- +* Codec supports frame-level multithreading.
- +*/
- +#define CODEC_CAP_FRAME_THREADS 0x0800
- //The following defines may change, don't expect compatibility if you use them.
- #define MB_TYPE_INTRA4x4 0x0001
- @@ -988,7 +991,20 @@ typedef struct AVPanScan{
- * - decoding: Set by libavcodec\
- */\
- void *hwaccel_picture_private;\
- -
- +\
- + /**\
- + * the AVCodecContext which ff_thread_get_buffer() was last called on\
- + * - encoding: Set by libavcodec.\
- + * - decoding: Set by libavcodec.\
- + */\
- + struct AVCodecContext *owner;\
- +\
- + /**\
- + * used by multithreading to store frame-specific info\
- + * - encoding: Set by libavcodec.\
- + * - decoding: Set by libavcodec.\
- + */\
- + void *thread_opaque;
- #define FF_QSCALE_TYPE_MPEG1 0
- #define FF_QSCALE_TYPE_MPEG2 1
- @@ -1199,7 +1215,7 @@ typedef struct AVCodecContext {
- * If non NULL, 'draw_horiz_band' is called by the libavcodec
- * decoder to draw a horizontal band. It improves cache usage. Not
- * all codecs can do that. You must check the codec capabilities
- - * beforehand.
- + * beforehand. May be called by different threads at the same time.
- * The function is also used by hardware acceleration APIs.
- * It is called at least once during frame decoding to pass
- * the data needed for hardware render.
- @@ -1452,7 +1468,8 @@ typedef struct AVCodecContext {
- * height, as they normally need to be rounded up to the next multiple of 16.
- * if CODEC_CAP_DR1 is not set then get_buffer() must call
- * avcodec_default_get_buffer() instead of providing buffers allocated by
- - * some other means.
- + * some other means. May be called from a different thread if FF_THREAD_FRAME
- + * is set, but does not need to be reentrant.
- * - encoding: unused
- * - decoding: Set by libavcodec, user can override.
- */
- @@ -1461,7 +1478,9 @@ typedef struct AVCodecContext {
- /**
- * Called to release buffers which were allocated with get_buffer.
- * A released buffer can be reused in get_buffer().
- - * pic.data[*] must be set to NULL.
- + * pic.data[*] must be set to NULL. May be called by different threads
- + * if frame threading is enabled, but not more than one at the same time.
- + *
- * - encoding: unused
- * - decoding: Set by libavcodec, user can override.
- */
- @@ -1765,6 +1784,7 @@ typedef struct AVCodecContext {
- #define FF_DEBUG_VIS_QP 0x00002000
- #define FF_DEBUG_VIS_MB_TYPE 0x00004000
- #define FF_DEBUG_BUFFERS 0x00008000
- +#define FF_DEBUG_THREADS 0x00010000
- /**
- * debug
- @@ -2744,6 +2764,34 @@ typedef struct AVCodecContext {
- * - decoding: unused
- */
- int lpc_passes;
- +
- + /**
- + * Whether this is a copy of the context which had init() called on it.
- + * This is used by multithreading - shared tables and picture pointers
- + * should be freed from the original context only.
- + * - encoding: Set by libavcodec.
- + * - decoding: Set by libavcodec.
- + */
- + int is_copy;
- +
- + /**
- + * Which multithreading methods to use.
- + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread,
- + * so clients which require strictly conforming DTS must not use it.
- + *
- + * - encoding: Set by user, otherwise the default is used.
- + * - decoding: Set by user, otherwise the default is used.
- + */
- + int thread_type;
- +#define FF_THREAD_FRAME 1 //< Decode more than one frame at once
- +#define FF_THREAD_SLICE 2 //< Decode more than one part of a single frame at once
- +
- + /**
- + * Which multithreading methods are actually active at the moment.
- + * - encoding: Set by libavcodec.
- + * - decoding: Set by libavcodec.
- + */
- + int active_thread_type;
- } AVCodecContext;
- /**
- @@ -2786,7 +2834,28 @@ typedef struct AVCodec {
- const enum SampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
- const int64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
- uint8_t max_lowres; ///< maximum value for lowres supported by the decoder
- +
- AVClass *priv_class; ///< AVClass for the private context
- +
- + /**
- + * @defgroup framethreading Frame-level threading support functions.
- + * @{
- + */
- + /**
- + * If defined, called on thread contexts when they are created.
- + * If the codec allocates writable tables in init(), re-allocate them here.
- + * priv_data will be set to a copy of the original.
- + */
- + int (*init_thread_copy)(AVCodecContext *);
- + /**
- + * Copy necessary context variables from a previous thread context to the current one.
- + * If not defined, the next thread will start automatically; otherwise, the codec
- + * must call ff_thread_finish_setup().
- + *
- + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped.
- + */
- + int (*update_thread_context)(AVCodecContext *dst, AVCodecContext *src);
- + /** @} */
- } AVCodec;
- /**
- diff --git a/libavcodec/w32thread.c b/libavcodec/beosthread.c
- similarity index 51%
- copy from libavcodec/w32thread.c
- copy to libavcodec/beosthread.c
- index f7a1430..8045a48 100644
- --- a/libavcodec/w32thread.c
- +++ b/libavcodec/beosthread.c
- @@ -1,5 +1,5 @@
- /*
- - * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
- + * Copyright (c) 2004 François Revol <revol@free.fr>
- *
- * This file is part of FFmpeg.
- *
- @@ -21,51 +21,54 @@
- #include "avcodec.h"
- -#define WIN32_LEAN_AND_MEAN
- -#include <windows.h>
- -#include <process.h>
- +#include <OS.h>
- typedef struct ThreadContext{
- AVCodecContext *avctx;
- - HANDLE thread;
- - HANDLE work_sem;
- - HANDLE job_sem;
- - HANDLE done_sem;
- + thread_id thread;
- + sem_id work_sem;
- + sem_id done_sem;
- int (*func)(AVCodecContext *c, void *arg);
- - int (*func2)(AVCodecContext *c, void *arg, int, int);
- void *arg;
- - int argsize;
- - int *jobnr;
- - int *ret;
- - int threadnr;
- + int ret;
- }ThreadContext;
- +// it's odd Be never patented that :D
- +struct benaphore {
- + vint32 atom;
- + sem_id sem;
- +};
- +static inline int lock_ben(struct benaphore *ben)
- +{
- + if (atomic_add(&ben->atom, 1) > 0)
- + return acquire_sem(ben->sem);
- + return B_OK;
- +}
- +static inline int unlock_ben(struct benaphore *ben)
- +{
- + if (atomic_add(&ben->atom, -1) > 1)
- + return release_sem(ben->sem);
- + return B_OK;
- +}
- -static unsigned WINAPI attribute_align_arg thread_func(void *v){
- +static struct benaphore av_thread_lib_ben;
- +
- +static int32 ff_thread_func(void *v){
- ThreadContext *c= v;
- for(;;){
- - int ret, jobnr;
- //printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
- - WaitForSingleObject(c->work_sem, INFINITE);
- - // avoid trying to access jobnr if we should quit
- - if (!c->func && !c->func2)
- - break;
- - WaitForSingleObject(c->job_sem, INFINITE);
- - jobnr = (*c->jobnr)++;
- - ReleaseSemaphore(c->job_sem, 1, 0);
- + acquire_sem(c->work_sem);
- //printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
- if(c->func)
- - ret= c->func(c->avctx, (uint8_t *)c->arg + jobnr*c->argsize);
- + c->ret= c->func(c->avctx, c->arg);
- else
- - ret= c->func2(c->avctx, c->arg, jobnr, c->threadnr);
- - if (c->ret)
- - c->ret[jobnr] = ret;
- + return 0;
- //printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
- - ReleaseSemaphore(c->done_sem, 1, 0);
- + release_sem(c->done_sem);
- }
- - return 0;
- + return B_OK;
- }
- /**
- @@ -75,20 +78,16 @@ static unsigned WINAPI attribute_align_arg thread_func(void *v){
- void avcodec_thread_free(AVCodecContext *s){
- ThreadContext *c= s->thread_opaque;
- int i;
- + int32 ret;
- for(i=0; i<s->thread_count; i++){
- c[i].func= NULL;
- - c[i].func2= NULL;
- + release_sem(c[i].work_sem);
- + wait_for_thread(c[i].thread, &ret);
- + if(c[i].work_sem > B_OK) delete_sem(c[i].work_sem);
- + if(c[i].done_sem > B_OK) delete_sem(c[i].done_sem);
- }
- - ReleaseSemaphore(c[0].work_sem, s->thread_count, 0);
- - for(i=0; i<s->thread_count; i++){
- - WaitForSingleObject(c[i].thread, INFINITE);
- - if(c[i].thread) CloseHandle(c[i].thread);
- - }
- - if(c[0].work_sem) CloseHandle(c[0].work_sem);
- - if(c[0].job_sem) CloseHandle(c[0].job_sem);
- - if(c[0].done_sem) CloseHandle(c[0].done_sem);
- av_freep(&s->thread_opaque);
- }
- @@ -96,40 +95,39 @@ void avcodec_thread_free(AVCodecContext *s){
- static int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size){
- ThreadContext *c= s->thread_opaque;
- int i;
- - int jobnr = 0;
- assert(s == c->avctx);
- + assert(count <= s->thread_count);
- /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
- - for(i=0; i<s->thread_count; i++){
- - c[i].arg= arg;
- - c[i].argsize= size;
- + for(i=0; i<count; i++){
- + c[i].arg= (char*)arg + i*size;
- c[i].func= func;
- - c[i].ret= ret;
- - c[i].jobnr = &jobnr;
- + c[i].ret= 12345;
- +
- + release_sem(c[i].work_sem);
- }
- - ReleaseSemaphore(c[0].work_sem, count, 0);
- - for(i=0; i<count; i++)
- - WaitForSingleObject(c[0].done_sem, INFINITE);
- + for(i=0; i<count; i++){
- + acquire_sem(c[i].done_sem);
- + c[i].func= NULL;
- + if(ret) ret[i]= c[i].ret;
- + }
- return 0;
- }
- -static int avcodec_thread_execute2(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count){
- - ThreadContext *c= s->thread_opaque;
- - int i;
- - for(i=0; i<s->thread_count; i++)
- - c[i].func2 = func;
- - avcodec_thread_execute(s, NULL, arg, ret, count, 0);
- -}
- -
- int avcodec_thread_init(AVCodecContext *s, int thread_count){
- int i;
- ThreadContext *c;
- - uint32_t threadid;
- +
- + if(!(s->thread_type & FF_THREAD_SLICE)){
- + av_log(s, AV_LOG_WARNING, "The requested thread algorithm is not supported with this thread library.\n");
- + return 0;
- + }
- s->thread_count= thread_count;
- + s->active_thread_type= FF_THREAD_SLICE;
- if (thread_count <= 1)
- return 0;
- @@ -137,32 +135,55 @@ int avcodec_thread_init(AVCodecContext *s, int thread_count){
- assert(!s->thread_opaque);
- c= av_mallocz(sizeof(ThreadContext)*thread_count);
- s->thread_opaque= c;
- - if(!(c[0].work_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL)))
- - goto fail;
- - if(!(c[0].job_sem = CreateSemaphore(NULL, 1, 1, NULL)))
- - goto fail;
- - if(!(c[0].done_sem = CreateSemaphore(NULL, 0, INT_MAX, NULL)))
- - goto fail;
- for(i=0; i<thread_count; i++){
- //printf("init semaphors %d\n", i); fflush(stdout);
- c[i].avctx= s;
- - c[i].work_sem = c[0].work_sem;
- - c[i].job_sem = c[0].job_sem;
- - c[i].done_sem = c[0].done_sem;
- - c[i].threadnr = i;
- +
- + if((c[i].work_sem = create_sem(0, "ff work sem")) < B_OK)
- + goto fail;
- + if((c[i].done_sem = create_sem(0, "ff done sem")) < B_OK)
- + goto fail;
- //printf("create thread %d\n", i); fflush(stdout);
- - c[i].thread = (HANDLE)_beginthreadex(NULL, 0, thread_func, &c[i], 0, &threadid );
- - if( !c[i].thread ) goto fail;
- + c[i].thread = spawn_thread(ff_thread_func, "libavcodec thread", B_LOW_PRIORITY, &c[i] );
- + if( c[i].thread < B_OK ) goto fail;
- + resume_thread(c[i].thread );
- }
- //printf("init done\n"); fflush(stdout);
- s->execute= avcodec_thread_execute;
- - s->execute2= avcodec_thread_execute2;
- return 0;
- fail:
- avcodec_thread_free(s);
- return -1;
- }
- +
- +/* provide a mean to serialize calls to avcodec_*() for thread safety. */
- +
- +int avcodec_thread_lock_lib(void)
- +{
- + return lock_ben(&av_thread_lib_ben);
- +}
- +
- +int avcodec_thread_unlock_lib(void)
- +{
- + return unlock_ben(&av_thread_lib_ben);
- +}
- +
- +/* our versions of _init and _fini (which are called by those actually from crt.o) */
- +
- +void initialize_after(void)
- +{
- + av_thread_lib_ben.atom = 0;
- + av_thread_lib_ben.sem = create_sem(0, "libavcodec benaphore");
- +}
- +
- +void uninitialize_before(void)
- +{
- + delete_sem(av_thread_lib_ben.sem);
- +}
- +
- +
- +
- diff --git a/libavcodec/dsputil.c b/libavcodec/dsputil.c
- index 29ddb4d..dd14eb4 100644
- --- a/libavcodec/dsputil.c
- +++ b/libavcodec/dsputil.c
- @@ -294,7 +294,7 @@ static int sse16_c(void *v, uint8_t *pix1, uint8_t *pix2, int line_size, int h)
- /* draw the edges of width 'w' of an image of size width, height */
- //FIXME check that this is ok for mpeg4 interlaced
- -static void draw_edges_c(uint8_t *buf, int wrap, int width, int height, int w)
- +static void draw_edges_c(uint8_t *buf, int wrap, int width, int height, int w, int sides)
- {
- uint8_t *ptr, *last_line;
- int i;
- @@ -302,8 +302,8 @@ static void draw_edges_c(uint8_t *buf, int wrap, int width, int height, int w)
- last_line = buf + (height - 1) * wrap;
- for(i=0;i<w;i++) {
- /* top and bottom */
- - memcpy(buf - (i + 1) * wrap, buf, width);
- - memcpy(last_line + (i + 1) * wrap, last_line, width);
- + if (sides&EDGE_TOP) memcpy(buf - (i + 1) * wrap, buf, width);
- + if (sides&EDGE_BOTTOM) memcpy(last_line + (i + 1) * wrap, last_line, width);
- }
- /* left and right */
- ptr = buf;
- @@ -314,10 +314,15 @@ static void draw_edges_c(uint8_t *buf, int wrap, int width, int height, int w)
- }
- /* corners */
- for(i=0;i<w;i++) {
- - memset(buf - (i + 1) * wrap - w, buf[0], w); /* top left */
- - memset(buf - (i + 1) * wrap + width, buf[width-1], w); /* top right */
- - memset(last_line + (i + 1) * wrap - w, last_line[0], w); /* top left */
- - memset(last_line + (i + 1) * wrap + width, last_line[width-1], w); /* top right */
- + if (sides&EDGE_TOP) {
- + memset(buf - (i + 1) * wrap - w, buf[0], w); /* top left */
- + memset(buf - (i + 1) * wrap + width, buf[width-1], w); /* top right */
- + }
- +
- + if (sides&EDGE_BOTTOM) {
- + memset(last_line + (i + 1) * wrap - w, last_line[0], w); /* top left */
- + memset(last_line + (i + 1) * wrap + width, last_line[width-1], w); /* top right */
- + }
- }
- }
- diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h
- index 6c56a65..55d7c2d 100644
- --- a/libavcodec/dsputil.h
- +++ b/libavcodec/dsputil.h
- @@ -484,8 +484,10 @@ typedef struct DSPContext {
- #define BASIS_SHIFT 16
- #define RECON_SHIFT 6
- - void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w);
- + void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w, int sides);
- #define EDGE_WIDTH 16
- +#define EDGE_TOP 1
- +#define EDGE_BOTTOM 2
- void (*prefetch)(void *mem, int stride, int h);
- diff --git a/libavcodec/options.c b/libavcodec/options.c
- index 6969d42..d41d8ce 100644
- --- a/libavcodec/options.c
- +++ b/libavcodec/options.c
- @@ -250,6 +250,7 @@ static const AVOption options[]={
- {"vis_qp", "visualize quantization parameter (QP), lower QP are tinted greener", 0, FF_OPT_TYPE_CONST, FF_DEBUG_VIS_QP, INT_MIN, INT_MAX, V|D, "debug"},
- {"vis_mb_type", "visualize block types", 0, FF_OPT_TYPE_CONST, FF_DEBUG_VIS_MB_TYPE, INT_MIN, INT_MAX, V|D, "debug"},
- {"buffers", "picture buffer allocations", 0, FF_OPT_TYPE_CONST, FF_DEBUG_BUFFERS, INT_MIN, INT_MAX, V|D, "debug"},
- +{"thread_ops", "threading operations", 0, FF_OPT_TYPE_CONST, FF_DEBUG_THREADS, INT_MIN, INT_MAX, V|D, "debug"},
- {"vismv", "visualize motion vectors (MVs)", OFFSET(debug_mv), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, V|D, "debug_mv"},
- {"pf", "forward predicted MVs of P-frames", 0, FF_OPT_TYPE_CONST, FF_DEBUG_VIS_MV_P_FOR, INT_MIN, INT_MAX, V|D, "debug_mv"},
- {"bf", "forward predicted MVs of B-frames", 0, FF_OPT_TYPE_CONST, FF_DEBUG_VIS_MV_B_FOR, INT_MIN, INT_MAX, V|D, "debug_mv"},
- @@ -425,6 +426,9 @@ static const AVOption options[]={
- {"levinson", NULL, 0, FF_OPT_TYPE_CONST, AV_LPC_TYPE_LEVINSON, INT_MIN, INT_MAX, A|E, "lpc_type"},
- {"cholesky", NULL, 0, FF_OPT_TYPE_CONST, AV_LPC_TYPE_CHOLESKY, INT_MIN, INT_MAX, A|E, "lpc_type"},
- {"lpc_passes", "number of passes to use for Cholesky factorization during LPC analysis", OFFSET(lpc_passes), FF_OPT_TYPE_INT, -1, INT_MIN, INT_MAX, A|E},
- +{"thread_type", "select multithreading type", OFFSET(thread_type), FF_OPT_TYPE_INT, FF_THREAD_SLICE|FF_THREAD_FRAME, 0, INT_MAX, V|E|D, "thread_type"},
- +{"slice", NULL, 0, FF_OPT_TYPE_CONST, FF_THREAD_SLICE, INT_MIN, INT_MAX, V|E|D, "thread_type"},
- +{"frame", NULL, 0, FF_OPT_TYPE_CONST, FF_THREAD_FRAME, INT_MIN, INT_MAX, V|E|D, "thread_type"},
- {NULL},
- };
- diff --git a/libavcodec/os2thread.c b/libavcodec/os2thread.c
- new file mode 100644
- index 0000000..9f0cd41
- --- /dev/null
- +++ b/libavcodec/os2thread.c
- @@ -0,0 +1,154 @@
- +/*
- + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
- + *
- + * This file is part of FFmpeg.
- + *
- + * FFmpeg is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * FFmpeg is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with FFmpeg; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +//#define DEBUG
- +
- +// Ported by Vlad Stelmahovsky
- +
- +#include "avcodec.h"
- +
- +#define INCL_DOS
- +#define INCL_DOSERRORS
- +#define INCL_DOSDEVIOCTL
- +#include <os2.h>
- +
- +typedef struct ThreadContext{
- + AVCodecContext *avctx;
- + int thread;
- + HEV work_sem;
- + HEV done_sem;
- + int (*func)(AVCodecContext *c, void *arg);
- + void *arg;
- + int ret;
- +}ThreadContext;
- +
- +
- +static void attribute_align_arg thread_func(void *v){
- + ThreadContext *c= v;
- +
- + for(;;){
- + //printf("thread_func %X enter wait\n", (int)v); fflush(stdout);
- + DosWaitEventSem(c->work_sem, SEM_INDEFINITE_WAIT);
- +// WaitForSingleObject(c->work_sem, INFINITE);
- +//printf("thread_func %X after wait (func=%X)\n", (int)v, (int)c->func); fflush(stdout);
- + if(c->func)
- + c->ret= c->func(c->avctx, c->arg);
- + else
- + return;
- + //printf("thread_func %X signal complete\n", (int)v); fflush(stdout);
- + DosPostEventSem(c->done_sem);
- +// ReleaseSemaphore(c->done_sem, 1, 0);
- + }
- +
- + return;
- +}
- +
- +/**
- + * free what has been allocated by avcodec_thread_init().
- + * must be called after decoding has finished, especially do not call while avcodec_thread_execute() is running
- + */
- +void avcodec_thread_free(AVCodecContext *s){
- + ThreadContext *c= s->thread_opaque;
- + int i;
- +
- + for(i=0; i<s->thread_count; i++){
- +
- + c[i].func= NULL;
- + DosPostEventSem(c[i].work_sem);
- + // ReleaseSemaphore(c[i].work_sem, 1, 0);
- + DosWaitThread((PTID)&c[i].thread,DCWW_WAIT);
- +// WaitForSingleObject(c[i].thread, INFINITE);
- + if(c[i].work_sem) DosCloseEventSem(c[i].work_sem);//CloseHandle(c[i].work_sem);
- + if(c[i].done_sem) DosCloseEventSem(c[i].done_sem);//CloseHandle(c[i].done_sem);
- + }
- +
- + av_freep(&s->thread_opaque);
- +}
- +
- +static int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size){
- + ThreadContext *c= s->thread_opaque;
- + int i;
- +
- + assert(s == c->avctx);
- + assert(count <= s->thread_count);
- +
- + /* note, we can be certain that this is not called with the same AVCodecContext by different threads at the same time */
- +
- + for(i=0; i<count; i++){
- +
- + c[i].arg= (char*)arg + i*size;
- + c[i].func= func;
- + c[i].ret= 12345;
- +
- + DosPostEventSem(c[i].work_sem);
- +// ReleaseSemaphore(c[i].work_sem, 1, 0);
- + }
- + for(i=0; i<count; i++){
- + DosWaitEventSem(c[i].done_sem,SEM_INDEFINITE_WAIT);
- +// WaitForSingleObject(c[i].done_sem, INFINITE);
- +
- + c[i].func= NULL;
- + if(ret) ret[i]= c[i].ret;
- + }
- + return 0;
- +}
- +
- +int avcodec_thread_init(AVCodecContext *s, int thread_count){
- + int i;
- + ThreadContext *c;
- + uint32_t threadid;
- +
- + if(!(s->thread_type & FF_THREAD_SLICE)){
- + av_log(s, AV_LOG_WARNING, "The requested thread algorithm is not supported with this thread library.\n");
- + return 0;
- + }
- +
- + s->thread_count= thread_count;
- + s->active_thread_type= FF_THREAD_SLICE;
- +
- + if (thread_count <= 1)
- + return 0;
- +
- + assert(!s->thread_opaque);
- + c= av_mallocz(sizeof(ThreadContext)*thread_count);
- + s->thread_opaque= c;
- +
- + for(i=0; i<thread_count; i++){
- +//printf("init semaphors %d\n", i); fflush(stdout);
- + c[i].avctx= s;
- +
- + if (DosCreateEventSem(NULL,&c[i].work_sem,DC_SEM_SHARED,0))
- + goto fail;
- + if (DosCreateEventSem(NULL,&c[i].done_sem,DC_SEM_SHARED,0))
- + goto fail;
- +
- +//printf("create thread %d\n", i); fflush(stdout);
- +// c[i].thread = (HANDLE)_beginthreadex(NULL, 0, thread_func, &c[i], 0, &threadid );
- + c[i].thread = _beginthread(thread_func, NULL, 0x10000, &c[i]);
- + if( c[i].thread <= 0 ) goto fail;
- + }
- +//printf("init done\n"); fflush(stdout);
- +
- + s->execute= avcodec_thread_execute;
- +
- + return 0;
- +fail:
- + avcodec_thread_free(s);
- + return -1;
- +}
- diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c
- index 1628b21..d2b0c3f 100644
- --- a/libavcodec/pthread.c
- +++ b/libavcodec/pthread.c
- @@ -1,5 +1,6 @@
- /*
- * Copyright (c) 2004 Roman Shaposhnik
- + * Copyright (c) 2008 Alexander Strange (astrange@ithinksw.com)
- *
- * Many thanks to Steven M. Schultz for providing clever ideas and
- * to Michael Niedermayer <michaelni@gmx.at> for writing initial
- @@ -24,6 +25,10 @@
- #include <pthread.h>
- #include "avcodec.h"
- +#include "thread.h"
- +
- +/// Max number of frame buffers that can be allocated when using frame threads.
- +#define MAX_BUFFERS 32
- typedef int (action_func)(AVCodecContext *c, void *arg);
- typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr);
- @@ -45,6 +50,66 @@ typedef struct ThreadContext {
- int done;
- } ThreadContext;
- +typedef struct PerThreadContext {
- + struct FrameThreadContext *parent;
- +
- + pthread_t thread;
- + pthread_cond_t input_cond; ///< Used to wait for a new frame from the main thread.
- + pthread_cond_t progress_cond; ///< Used by child threads to wait for decoding/encoding progress.
- + 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 frames passed to this thread.
- +
- + AVPacket avpkt; ///< Input frame (for decoding) or output (for encoding).
- + int allocated_buf_size;
- +
- + AVFrame picture; ///< Output frame (for decoding) or input (for encoding).
- + int got_picture; ///< The output of got_picture_ptr from the last avcodec_decode_video() call (for decoding).
- + int result; ///< The result of the last codec decode/encode() call.
- +
- + enum {
- + STATE_INPUT_READY, ///< Set when the thread is sleeping.
- + STATE_SETTING_UP, ///< Set before the codec has called ff_thread_finish_setup().
- + STATE_SETUP_FINISHED /**<
- + * Set after the codec has called ff_thread_finish_setup().
- + * At this point it is safe to start the next thread.
- + */
- + } state;
- +
- + /**
- + * Array of frames passed to ff_thread_release_buffer(),
- + * to be released later.
- + */
- + AVFrame released_buffers[MAX_BUFFERS];
- + int num_released_buffers;
- +
- + /**
- + * Array of progress values for ff_thread_get_buffer().
- + */
- + int progress[MAX_BUFFERS][2];
- + uint8_t used_progress[MAX_BUFFERS];
- +} PerThreadContext;
- +
- +typedef struct FrameThreadContext {
- + PerThreadContext *threads; ///< The contexts for frame decoding threads.
- + PerThreadContext *prev_thread; ///< The last thread submit_frame() was called on.
- +
- + pthread_mutex_t buffer_mutex; ///< Mutex used to protect get/release_buffer().
- +
- + int next_decoding; ///< The next context to submit frames to.
- + int next_finished; ///< The next context to return output from.
- +
- + int delaying; /**
- + * Set for the first N frames, where N is the number of threads.
- + * While it is set, ff_en/decode_frame_threaded won't return any results.
- + */
- +
- + int die; ///< Set to cause threads to exit.
- +} FrameThreadContext;
- +
- static void* attribute_align_arg worker(void *v)
- {
- AVCodecContext *avctx = v;
- @@ -84,7 +149,7 @@ static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int t
- pthread_mutex_unlock(&c->current_job_lock);
- }
- -void avcodec_thread_free(AVCodecContext *avctx)
- +static void thread_free(AVCodecContext *avctx)
- {
- ThreadContext *c = avctx->thread_opaque;
- int i;
- @@ -109,6 +174,9 @@ static int avcodec_thread_execute(AVCodecContext *avctx, action_func* func, void
- ThreadContext *c= avctx->thread_opaque;
- int dummy_ret;
- + if (!(avctx->active_thread_type&FF_THREAD_SLICE) || avctx->thread_count <= 1)
- + return avcodec_default_execute(avctx, func, arg, ret, job_count, job_size);
- +
- if (job_count <= 0)
- return 0;
- @@ -140,10 +208,11 @@ static int avcodec_thread_execute2(AVCodecContext *avctx, action_func2* func2, v
- return avcodec_thread_execute(avctx, NULL, arg, ret, job_count, 0);
- }
- -int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
- +static int thread_init(AVCodecContext *avctx)
- {
- int i;
- ThreadContext *c;
- + int thread_count = avctx->thread_count;
- avctx->thread_count = thread_count;
- @@ -184,3 +253,549 @@ int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
- avctx->execute2 = avcodec_thread_execute2;
- return 0;
- }
- +
- +/**
- + * Read and decode frames from the main thread until fctx->die is set.
- + * ff_thread_finish_setup() is called before decoding if the codec
- + * doesn't define update_thread_context(), and afterwards if the codec errors
- + * before calling it.
- + */
- +static attribute_align_arg void *frame_worker_thread(void *arg)
- +{
- + PerThreadContext *p = arg;
- + FrameThreadContext *fctx = p->parent;
- + AVCodecContext *avctx = p->avctx;
- + AVCodec *codec = avctx->codec;
- +
- + while (1) {
- + if (p->state == STATE_INPUT_READY && !fctx->die) {
- + pthread_mutex_lock(&p->mutex);
- + while (p->state == STATE_INPUT_READY && !fctx->die)
- + pthread_cond_wait(&p->input_cond, &p->mutex);
- + pthread_mutex_unlock(&p->mutex);
- + }
- +
- + if (fctx->die) break;
- +
- + if (!codec->update_thread_context) ff_thread_finish_setup(avctx);
- +
- + pthread_mutex_lock(&p->mutex);
- + p->result = codec->decode(avctx, &p->picture, &p->got_picture, &p->avpkt);
- +
- + if (p->state == STATE_SETTING_UP) ff_thread_finish_setup(avctx);
- +
- + p->state = STATE_INPUT_READY;
- +
- + pthread_mutex_lock(&p->progress_mutex);
- + pthread_cond_signal(&p->output_cond);
- + pthread_mutex_unlock(&p->progress_mutex);
- + pthread_mutex_unlock(&p->mutex);
- + };
- +
- + return NULL;
- +}
- +
- +/**
- + * Update a thread's context from the last thread. This is used for returning
- + * frames and for starting new decoding jobs after the previous one finishes
- + * predecoding.
- + *
- + * @param dst The destination context.
- + * @param src The source context.
- + * @param for_user Whether or not dst is the user-visible context. update_thread_context won't be called and some pointers will be copied.
- + */
- +static int update_thread_context_from_copy(AVCodecContext *dst, AVCodecContext *src, int for_user)
- +{
- + int err = 0;
- +#define COPY(f) dst->f = src->f;
- +#define COPY_FIELDS(s, e) memcpy(&dst->s, &src->s, (char*)&dst->e - (char*)&dst->s);
- +
- + //coded_width/height are not copied here, so that codecs' update_thread_context can see when they change
- + //many encoding parameters could be theoretically changed during encode, but aren't copied ATM
- +
- + if (dst != src) {
- + COPY(sub_id);
- + COPY(time_base);
- + COPY(width);
- + COPY(height);
- + COPY(pix_fmt);
- + COPY(real_pict_num); //necessary?
- + COPY(delay);
- + COPY(max_b_frames);
- +
- + COPY_FIELDS(mv_bits, opaque);
- +
- + COPY(has_b_frames);
- + COPY(bits_per_coded_sample);
- + COPY(sample_aspect_ratio);
- + COPY(idct_algo);
- + memcpy(dst->error, src->error, sizeof(src->error));
- + COPY(last_predictor_count); //necessary?
- + COPY(dtg_active_format);
- + COPY(color_table_id);
- + COPY(profile);
- + COPY(level);
- + COPY(bits_per_raw_sample);
- + COPY(ticks_per_frame);
- + COPY(color_primaries);
- + COPY(color_trc);
- + COPY(colorspace);
- + COPY(color_range);
- + }
- +
- + if (for_user) {
- + COPY(coded_frame);
- + dst->has_b_frames += src->thread_count - 1;
- + } else {
- + if (dst->codec->update_thread_context)
- + err = dst->codec->update_thread_context(dst, src);
- + }
- +
- + return err;
- +}
- +
- +///Update the next decoding thread with values set by the user
- +static void update_thread_context_from_user(AVCodecContext *dst, AVCodecContext *src)
- +{
- + COPY(get_buffer);
- + COPY(release_buffer);
- + COPY(opaque);
- + COPY(hurry_up);
- + COPY_FIELDS(skip_loop_filter, bidir_refine);
- + COPY(frame_number);
- + COPY(reordered_opaque);
- +}
- +
- +static void free_progress(AVFrame *f)
- +{
- + PerThreadContext *p = f->owner->thread_opaque;
- + int *progress = f->thread_opaque;
- +
- + p->used_progress[(progress - p->progress[0]) / 2] = 0;
- +}
- +
- +/// Release all frames passed to ff_thread_release_buffer()
- +static void handle_delayed_releases(PerThreadContext *p)
- +{
- + FrameThreadContext *fctx = p->parent;
- +
- + while (p->num_released_buffers > 0) {
- + AVFrame *f = &p->released_buffers[--p->num_released_buffers];
- +
- + pthread_mutex_lock(&fctx->buffer_mutex);
- + free_progress(f);
- + f->thread_opaque = NULL;
- +
- + f->owner->release_buffer(f->owner, f);
- + pthread_mutex_unlock(&fctx->buffer_mutex);
- + }
- +}
- +
- +/// Submit a frame to the next decoding thread
- +static int submit_frame(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;
- + int err = 0;
- +
- + if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0;
- +
- + pthread_mutex_lock(&p->mutex);
- +
- + handle_delayed_releases(p);
- +
- + if (prev_thread) {
- + 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_thread_context_from_copy(p->avctx, prev_thread->avctx, 0);
- + if (err) 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);
- +
- + fctx->prev_thread = p;
- +
- + return err;
- +}
- +
- +int ff_thread_decode_frame(AVCodecContext *avctx,
- + void *data, int *data_size,
- + AVPacket *avpkt)
- +{
- + FrameThreadContext *fctx = avctx->thread_opaque;
- + int thread_count = avctx->thread_count, err = 0;
- + int returning_thread = fctx->next_finished;
- + PerThreadContext *p;
- +
- + p = &fctx->threads[fctx->next_decoding];
- + update_thread_context_from_user(p->avctx, avctx);
- + err = submit_frame(p, avpkt);
- + if (err) return err;
- +
- + fctx->next_decoding++;
- +
- + if (fctx->delaying && avpkt->size) {
- + if (fctx->next_decoding >= (thread_count-1)) fctx->delaying = 0;
- +
- + *data_size=0;
- + return 0;
- + }
- +
- + //If it's draining frames at EOF, ignore null frames from the codec.
- + //Only return one when we've run out of codec frames to return.
- + do {
- + p = &fctx->threads[returning_thread++];
- +
- + 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);
- + }
- +
- + *(AVFrame*)data = p->picture;
- + *data_size = p->got_picture;
- +
- + avcodec_get_frame_defaults(&p->picture);
- + p->got_picture = 0;
- +
- + if (returning_thread >= thread_count) returning_thread = 0;
- + } while (!avpkt->size && !*data_size && returning_thread != fctx->next_finished);
- +
- + update_thread_context_from_copy(avctx, p->avctx, 1);
- +
- + if (fctx->next_decoding >= thread_count) fctx->next_decoding = 0;
- + fctx->next_finished = returning_thread;
- +
- + return p->result;
- +}
- +
- +void ff_thread_report_progress(AVFrame *f, int n, int field)
- +{
- + PerThreadContext *p;
- + int *progress = f->thread_opaque;
- +
- + if (!progress || progress[field] >= n) return;
- +
- + p = f->owner->thread_opaque;
- +
- + if (f->owner->debug&FF_DEBUG_THREADS)
- + av_log(f->owner, AV_LOG_DEBUG, "%p finished %d field %d\n", progress, n, field);
- +
- + pthread_mutex_lock(&p->progress_mutex);
- + progress[field] = n;
- + pthread_cond_broadcast(&p->progress_cond);
- + pthread_mutex_unlock(&p->progress_mutex);
- +}
- +
- +void ff_thread_await_progress(AVFrame *f, int n, int field)
- +{
- + PerThreadContext *p;
- + int *progress = f->thread_opaque;
- +
- + if (!progress || progress[field] >= n) return;
- +
- + p = f->owner->thread_opaque;
- +
- + if (f->owner->debug&FF_DEBUG_THREADS)
- + av_log(f->owner, AV_LOG_DEBUG, "thread awaiting %d field %d from %p\n", n, field, progress);
- +
- + pthread_mutex_lock(&p->progress_mutex);
- + while (progress[field] < n)
- + pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
- + pthread_mutex_unlock(&p->progress_mutex);
- +}
- +
- +void ff_thread_finish_frame(AVFrame *f)
- +{
- + ff_thread_report_progress(f, INT_MAX, 0);
- + ff_thread_report_progress(f, INT_MAX, 1);
- +}
- +
- +void ff_thread_finish_setup(AVCodecContext *avctx) {
- + PerThreadContext *p = avctx->thread_opaque;
- +
- + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
- +
- + pthread_mutex_lock(&p->progress_mutex);
- + p->state = STATE_SETUP_FINISHED;
- + pthread_cond_broadcast(&p->progress_cond);
- + pthread_mutex_unlock(&p->progress_mutex);
- +}
- +
- +/// Wait for all threads to finish decoding
- +static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count)
- +{
- + int i;
- +
- + for (i = 0; i < thread_count; i++) {
- + PerThreadContext *p = &fctx->threads[i];
- +
- + 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);
- + }
- + }
- +}
- +
- +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)
- + update_thread_context_from_copy(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);
- +
- + pthread_join(p->thread, NULL);
- +
- + if (codec->close)
- + codec->close(p->avctx);
- +
- + handle_delayed_releases(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);
- + }
- +
- + av_freep(&fctx->threads);
- + pthread_mutex_destroy(&fctx->buffer_mutex);
- + av_freep(&avctx->thread_opaque);
- +}
- +
- +static int frame_thread_init(AVCodecContext *avctx)
- +{
- + FrameThreadContext *fctx;
- + AVCodecContext *src = avctx;
- + AVCodec *codec = avctx->codec;
- + int i, thread_count = avctx->thread_count, err = 0;
- +
- + avctx->thread_opaque = fctx = av_mallocz(sizeof(FrameThreadContext));
- + fctx->delaying = 1;
- + pthread_mutex_init(&fctx->buffer_mutex, NULL);
- +
- + fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count);
- +
- + 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;
- +
- + *copy = *src;
- + copy->thread_opaque = p;
- +
- + if (!i) {
- + src = copy;
- +
- + if (codec->init)
- + err = codec->init(copy);
- + } else {
- + copy->is_copy = 1;
- + copy->priv_data = av_malloc(codec->priv_data_size);
- + memcpy(copy->priv_data, src->priv_data, codec->priv_data_size);
- +
- + if (codec->init_thread_copy)
- + err = codec->init_thread_copy(copy);
- + }
- +
- + if (err) goto error;
- +
- + pthread_create(&p->thread, NULL, frame_worker_thread, p);
- + }
- +
- + update_thread_context_from_copy(avctx, src, 1);
- +
- + return 0;
- +
- +error:
- + // the failed thread isn't completed but must be freed
- + frame_thread_free(avctx, i+1);
- +
- + return err;
- +}
- +
- +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)
- + update_thread_context_from_copy(fctx->threads->avctx, fctx->prev_thread->avctx, 0);
- +
- + fctx->next_decoding = fctx->next_finished = 0;
- + fctx->delaying = 1;
- + fctx->prev_thread = NULL;
- +}
- +
- +static int *allocate_progress(PerThreadContext *p)
- +{
- + int i;
- +
- + for (i = 0; i < MAX_BUFFERS; i++)
- + if (!p->used_progress[i]) break;
- +
- + if (i == MAX_BUFFERS) {
- + av_log(p->avctx, AV_LOG_ERROR, "allocate_progress() overflow\n");
- + return NULL;
- + }
- +
- + p->used_progress[i] = 1;
- +
- + return p->progress[i];
- +}
- +
- +int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
- +{
- + int ret, *progress;
- + PerThreadContext *p = avctx->thread_opaque;
- +
- + f->owner = avctx;
- +
- + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) {
- + f->thread_opaque = NULL;
- + return avctx->get_buffer(avctx, f);
- + }
- +
- + pthread_mutex_lock(&p->parent->buffer_mutex);
- + f->thread_opaque = progress = allocate_progress(p);
- +
- + if (!progress) {
- + pthread_mutex_unlock(&p->parent->buffer_mutex);
- + return -1;
- + }
- +
- + progress[0] =
- + progress[1] = -1;
- +
- + ret = avctx->get_buffer(avctx, f);
- + pthread_mutex_unlock(&p->parent->buffer_mutex);
- +
- + /*
- + * The buffer list isn't shared between threads,
- + * so age doesn't mean what codecs expect it to mean.
- + * Disable it for now.
- + */
- + f->age = INT_MAX;
- +
- + return ret;
- +}
- +
- +void ff_thread_release_buffer(AVCodecContext *avctx, AVFrame *f)
- +{
- + PerThreadContext *p = avctx->thread_opaque;
- +
- + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) {
- + avctx->release_buffer(avctx, f);
- + return;
- + }
- +
- + if (p->num_released_buffers >= MAX_BUFFERS) {
- + av_log(p->avctx, AV_LOG_ERROR, "too many delayed release_buffer calls!\n");
- + return;
- + }
- +
- + if(avctx->debug & FF_DEBUG_BUFFERS)
- + av_log(avctx, AV_LOG_DEBUG, "delayed_release_buffer called on pic %p, %d buffers used\n",
- + f, f->owner->internal_buffer_count);
- +
- + p->released_buffers[p->num_released_buffers++] = *f;
- + memset(f->data, 0, sizeof(f->data));
- +}
- +
- +/// Set the threading algorithm used, or none if an algorithm was set but no thread count.
- +static void validate_thread_parameters(AVCodecContext *avctx)
- +{
- + int frame_threading_supported = (avctx->codec->capabilities & CODEC_CAP_FRAME_THREADS)
- + && !(avctx->flags & CODEC_FLAG_TRUNCATED)
- + && !(avctx->flags & CODEC_FLAG_LOW_DELAY)
- + && !(avctx->flags2 & CODEC_FLAG2_CHUNKS);
- + if (avctx->thread_count <= 1)
- + avctx->active_thread_type = 0;
- + else if (frame_threading_supported && (avctx->thread_type & FF_THREAD_FRAME))
- + avctx->active_thread_type = FF_THREAD_FRAME;
- + else
- + avctx->active_thread_type = FF_THREAD_SLICE;
- +}
- +
- +int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
- +{
- + if (avctx->thread_opaque) {
- + av_log(avctx, AV_LOG_ERROR, "avcodec_thread_init called after avcodec_open, this does nothing in ffmpeg-mt\n");
- + return -1;
- + }
- +
- + avctx->thread_count = thread_count;
- +
- + if (avctx->codec) {
- + validate_thread_parameters(avctx);
- +
- + if (avctx->active_thread_type&FF_THREAD_SLICE)
- + return thread_init(avctx);
- + else if (avctx->active_thread_type&FF_THREAD_FRAME)
- + return frame_thread_init(avctx);
- + }
- +
- + return 0;
- +}
- +
- +void avcodec_thread_free(AVCodecContext *avctx)
- +{
- + if (avctx->active_thread_type&FF_THREAD_FRAME)
- + frame_thread_free(avctx, avctx->thread_count);
- + else
- + thread_free(avctx);
- +}
- diff --git a/libavcodec/thread.h b/libavcodec/thread.h
- new file mode 100644
- index 0000000..dc4029e
- --- /dev/null
- +++ b/libavcodec/thread.h
- @@ -0,0 +1,112 @@
- +/*
- + * Multithreading support
- + * Copyright (c) 2008 Alexander Strange <astrange@ithinksw.com>
- + *
- + * This file is part of FFmpeg.
- + *
- + * FFmpeg is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * FFmpeg is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with FFmpeg; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +/**
- + * @file thread.h
- + * Multithreading support header.
- + * @author Alexander Strange <astrange@ithinksw.com>
- + */
- +
- +#ifndef AVCODEC_THREAD_H
- +#define AVCODEC_THREAD_H
- +
- +#include "config.h"
- +#include "avcodec.h"
- +
- +/**
- + * Waits for decoding threads to finish and resets the internal
- + * state. Called by avcodec_flush_buffers().
- + */
- +void ff_thread_flush(AVCodecContext *avctx);
- +
- +/**
- + * Submits a new frame to a decoding thread. Parameters are the
- + * same as avcodec_decode_video2(). Returns the earliest available
- + * decoded picture.
- + *
- + * NULL AVFrames returned from the codec will be dropped if
- + * the client passes NULL data in.
- + */
- +int ff_thread_decode_frame(AVCodecContext *avctx,
- + void *data, int *data_size,
- + AVPacket *avpkt);
- +
- +/**
- + * For codecs which define update_thread_context.
- + * Call this when the context is set up for the next frame to be
- + * decoded. The next decoding thread will start afterwards.
- + * The codec must not modify parts of the context read by
- + * update_thread_context after calling this or it will cause a race
- + * condition.
- + */
- +void ff_thread_finish_setup(AVCodecContext *avctx);
- +
- +/**
- + * Call this when some part of the picture is finished decoding.
- + * Later calls with lower progress values will be ignored.
- + *
- + * @param f The AVFrame containing the current field or frame
- + * @param progress The highest-numbered part finished so far
- + * @param field The field being decoded, for field pictures.
- + * 0 for top field or progressive, 1 for bottom.
- + */
- +void ff_thread_report_progress(AVFrame *f, int progress, int field);
- +
- +/**
- + * Call this before accessing some part of a previous field or frame.
- + * Returns after the previous decoding thread has called ff_thread_report_progress()
- + * with sufficiently high progress.
- + *
- + * @param f The AVFrame containing the reference field or frame
- + * @param progress The highest-numbered part of the reference picture to wait for
- + * @param field The field being referenced, for field pictures.
- + * 0 for top field or progressive, 1 for bottom.
- + */
- +void ff_thread_await_progress(AVFrame *f, int progress, int field);
- +
- +/**
- + * Convenience function to set progress for both fields to INT_MAX.
- + * Can be used to prevent deadlocks in later threads when a decoder
- + * exits early due to errors.
- + *
- + * @param f The frame or field picture being decoded.
- + */
- +void ff_thread_finish_frame(AVFrame *f);
- +
- +/**
- + * Replacement for get_buffer() for frame-level threading.
- + *
- + * Codecs with CODEC_CAP_FRAME_THREADS must call this instead
- + * of calling get_buffer() directly.
- + */
- +int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f);
- +
- +/**
- + * Replacement for release_buffer() for frame-level threading.
- + *
- + * Codecs with CODEC_CAP_FRAME_THREADS must call this instead
- + * of calling release_buffer() directly.
- + *
- + * On return, \p f->data will be cleared.
- + */
- +void ff_thread_release_buffer(AVCodecContext *avctx, AVFrame *f);
- +
- +#endif /* AVCODEC_THREAD_H */
- diff --git a/libavcodec/utils.c b/libavcodec/utils.c
- index ffd34ee..ea2b5f0 100644
- --- a/libavcodec/utils.c
- +++ b/libavcodec/utils.c
- @@ -34,6 +34,7 @@
- #include "dsputil.h"
- #include "libavutil/opt.h"
- #include "imgconvert.h"
- +#include "thread.h"
- #include "audioconvert.h"
- #include "internal.h"
- #include <stdlib.h>
- @@ -254,6 +255,11 @@ int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){
- (*picture_number)++;
- if(buf->base[0] && (buf->width != w || buf->height != h || buf->pix_fmt != s->pix_fmt)){
- + if(s->active_thread_type&FF_THREAD_FRAME) {
- + av_log_missing_feature(s, "Width/height changing with frame threads is", 0);
- + return -1;
- + }
- +
- for(i=0; i<4; i++){
- av_freep(&buf->base[i]);
- buf->data[i]= NULL;
- @@ -352,6 +358,7 @@ void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){
- assert(pic->type==FF_BUFFER_TYPE_INTERNAL);
- assert(s->internal_buffer_count);
- + if(s->internal_buffer){
- buf = NULL; /* avoids warning */
- for(i=0; i<s->internal_buffer_count; i++){ //just 3-5 checks so is not worth to optimize
- buf= &((InternalBuffer*)s->internal_buffer)[i];
- @@ -363,6 +370,7 @@ void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){
- last = &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];
- FFSWAP(InternalBuffer, *buf, *last);
- + }
- for(i=0; i<4; i++){
- pic->data[i]=NULL;
- @@ -515,18 +523,29 @@ int attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec)
- goto free_and_end;
- }
- avctx->frame_number = 0;
- +
- + if (HAVE_THREADS && !avctx->thread_opaque) {
- + ret = avcodec_thread_init(avctx, avctx->thread_count);
- + if (ret < 0) {
- + goto free_and_end;
- + }
- + }
- +
- if (avctx->codec->max_lowres < avctx->lowres) {
- av_log(avctx, AV_LOG_ERROR, "The maximum value for lowres supported by the decoder is %d\n",
- avctx->codec->max_lowres);
- goto free_and_end;
- }
- - if(avctx->codec->init){
- - ret = avctx->codec->init(avctx);
- - if (ret < 0) {
- - goto free_and_end;
- + if(avctx->codec->init && !(avctx->active_thread_type&FF_THREAD_FRAME)){
- + if(avctx->codec->init){
- + ret = avctx->codec->init(avctx);
- + if (ret < 0) {
- + goto free_and_end;
- + }
- }
- }
- +
- ret=0;
- end:
- entangled_thread_counter--;
- @@ -612,12 +631,15 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
- AVPacket *avpkt)
- {
- int ret;
- + int threaded = avctx->active_thread_type&FF_THREAD_FRAME;
- *got_picture_ptr= 0;
- if((avctx->coded_width||avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
- return -1;
- - if((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size){
- - ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
- + if((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || threaded){
- + if (HAVE_PTHREADS && threaded) ret = ff_thread_decode_frame(avctx, picture,
- + got_picture_ptr, avpkt);
- + else ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
- avpkt);
- emms_c(); //needed to avoid an emms_c() call before every return;
- @@ -735,7 +757,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
- if (HAVE_THREADS && avctx->thread_opaque)
- avcodec_thread_free(avctx);
- - if (avctx->codec && avctx->codec->close)
- + if (avctx->codec && avctx->codec->close && !(avctx->active_thread_type&FF_THREAD_FRAME))
- avctx->codec->close(avctx);
- avcodec_default_free_buffers(avctx);
- avctx->coded_frame = NULL;
- @@ -743,6 +765,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
- if(avctx->codec && avctx->codec->encode)
- av_freep(&avctx->extradata);
- avctx->codec = NULL;
- + avctx->active_thread_type = 0;
- entangled_thread_counter--;
- /* Release any user-supplied mutex. */
- @@ -983,6 +1006,8 @@ void avcodec_init(void)
- void avcodec_flush_buffers(AVCodecContext *avctx)
- {
- + if(HAVE_PTHREADS && avctx->active_thread_type&FF_THREAD_FRAME)
- + ff_thread_flush(avctx);
- if(avctx->codec->flush)
- avctx->codec->flush(avctx);
- }
- @@ -1189,7 +1214,38 @@ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op))
- unsigned int ff_toupper4(unsigned int x)
- {
- return toupper( x &0xFF)
- - + (toupper((x>>8 )&0xFF)<<8 )
- - + (toupper((x>>16)&0xFF)<<16)
- - + (toupper((x>>24)&0xFF)<<24);
- + + (toupper((x>>8 )&0xFF)<<8 )
- + + (toupper((x>>16)&0xFF)<<16)
- + + (toupper((x>>24)&0xFF)<<24);
- +}
- +
- +#if !HAVE_PTHREADS
- +
- +int ff_thread_get_buffer(AVCodecContext *avctx, AVFrame *f)
- +{
- + f->owner = avctx;
- + return avctx->get_buffer(avctx, f);
- +}
- +
- +void ff_thread_release_buffer(AVCodecContext *avctx, AVFrame *f)
- +{
- + f->owner->release_buffer(f->owner, f);
- +}
- +
- +void ff_thread_finish_setup(AVCodecContext *avctx)
- +{
- +}
- +
- +void ff_thread_report_progress(AVFrame *f, int progress, int field)
- +{
- }
- +
- +void ff_thread_await_progress(AVFrame *f, int progress, int field)
- +{
- +}
- +
- +void ff_thread_finish_frame(AVFrame *f)
- +{
- +}
- +
- +#endif
- diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c
- index 59719e7..0f63a24 100644
- --- a/libavcodec/vp3.c
- +++ b/libavcodec/vp3.c
- @@ -40,6 +40,7 @@
- #include "vp3data.h"
- #include "xiph.h"
- +#include "thread.h"
- #define FRAGMENT_PIXELS 8
- @@ -1318,6 +1319,12 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y)
- int h, cy;
- int offset[4];
- + if (HAVE_PTHREADS && s->avctx->active_thread_type&FF_THREAD_FRAME) {
- + int y_flipped = s->flipped_image ? s->avctx->height-y : y;
- +
- + ff_thread_report_progress(&s->current_frame, y_flipped==s->avctx->height ? s->avctx->height : y_flipped-1, 0);
- + }
- +
- if(s->avctx->draw_horiz_band==NULL)
- return;
- @@ -1339,6 +1346,32 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y)
- s->avctx->draw_horiz_band(s->avctx, &s->current_frame, offset, y, 3, h);
- }
- +/**
- + * Wait for the reference frame of a fragment.
- + * Units used are luma pixel rows.
- + */
- +static void await_reference_row(Vp3DecodeContext *s, Vp3Fragment *fragment, int motion_y, int y)
- +{
- + AVFrame *ref_frame;
- + int border = motion_y&1;
- + int max_row = s->avctx->height;
- + int ref_row;
- +
- + if (!HAVE_PTHREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME))
- + return;
- +
- + if (fragment->coding_method == MODE_USING_GOLDEN ||
- + fragment->coding_method == MODE_GOLDEN_MV)
- + ref_frame = &s->golden_frame;
- + else
- + ref_frame = &s->last_frame;
- +
- + ref_row = y + (motion_y >> 1);
- + ref_row = FFMAX(FFABS(ref_row), ref_row + 8 + border);
- +
- + ff_thread_await_progress(ref_frame, FFMIN(ref_row, max_row), 0);
- +}
- +
- /*
- * Perform the final rendering for a particular slice of data.
- * The slice number ranges from 0..(c_superblock_height - 1).
- @@ -1399,6 +1432,9 @@ static void render_slice(Vp3DecodeContext *s, int slice)
- first_pixel = 8*y*stride + 8*x;
- + if (s->all_fragments[i].coding_method != MODE_INTRA && !plane)
- + await_reference_row(s, &s->all_fragments[i], motion_val[y*fragment_width + x][1], (16*y) >> s->chroma_y_shift);
- +
- /* transform if this block was coded */
- if (s->all_fragments[i].coding_method != MODE_COPY) {
- if ((s->all_fragments[i].coding_method == MODE_USING_GOLDEN) ||
- @@ -1510,6 +1546,38 @@ static void render_slice(Vp3DecodeContext *s, int slice)
- vp3_draw_horiz_band(s, FFMIN((32 << s->chroma_y_shift) * (slice + 1) -16, s->height-16));
- }
- +/// Allocate tables for frame data in Vp3DecodeContext
- +static av_cold int allocate_tables(AVCodecContext *avctx)
- +{
- + Vp3DecodeContext *s = avctx->priv_data;
- + int y_fragment_count, c_fragment_count;
- +
- + y_fragment_count = s->fragment_width[0] * s->fragment_height[0];
- + c_fragment_count = s->fragment_width[1] * s->fragment_height[1];
- +
- + s->superblock_coding = av_malloc(s->superblock_count);
- + s->all_fragments = av_malloc(s->fragment_count * sizeof(Vp3Fragment));
- + s->coded_fragment_list[0] = av_malloc(s->fragment_count * sizeof(int));
- + s->dct_tokens_base = av_malloc(64*s->fragment_count * sizeof(*s->dct_tokens_base));
- + s->motion_val[0] = av_malloc(y_fragment_count * sizeof(*s->motion_val[0]));
- + s->motion_val[1] = av_malloc(c_fragment_count * sizeof(*s->motion_val[1]));
- +
- + /* work out the block mapping tables */
- + s->superblock_fragments = av_malloc(s->superblock_count * 16 * sizeof(int));
- + s->macroblock_coding = av_malloc(s->macroblock_count + 1);
- +
- + if (!s->superblock_coding || !s->all_fragments || !s->dct_tokens_base ||
- + !s->coded_fragment_list[0] || !s->superblock_fragments || !s->macroblock_coding ||
- + !s->motion_val[0] || !s->motion_val[1]) {
- + vp3_decode_end(avctx);
- + return -1;
- + }
- +
- + init_block_mapping(s);
- +
- + return 0;
- +}
- +
- /*
- * This is the ffmpeg/libavcodec API init function.
- */
- @@ -1559,7 +1627,6 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
- s->superblock_count = s->y_superblock_count + (s->c_superblock_count * 2);
- s->u_superblock_start = s->y_superblock_count;
- s->v_superblock_start = s->u_superblock_start + s->c_superblock_count;
- - s->superblock_coding = av_malloc(s->superblock_count);
- s->macroblock_width = (s->width + 15) / 16;
- s->macroblock_height = (s->height + 15) / 16;
- @@ -1577,18 +1644,6 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
- s->fragment_start[1] = y_fragment_count;
- s->fragment_start[2] = y_fragment_count + c_fragment_count;
- - s->all_fragments = av_malloc(s->fragment_count * sizeof(Vp3Fragment));
- - s->coded_fragment_list[0] = av_malloc(s->fragment_count * sizeof(int));
- - s->dct_tokens_base = av_malloc(64*s->fragment_count * sizeof(*s->dct_tokens_base));
- - s->motion_val[0] = av_malloc(y_fragment_count * sizeof(*s->motion_val[0]));
- - s->motion_val[1] = av_malloc(c_fragment_count * sizeof(*s->motion_val[1]));
- -
- - if (!s->superblock_coding || !s->all_fragments || !s->dct_tokens_base ||
- - !s->coded_fragment_list[0] || !s->motion_val[0] || !s->motion_val[1]) {
- - vp3_decode_end(avctx);
- - return -1;
- - }
- -
- if (!s->theora_tables)
- {
- for (i = 0; i < 64; i++) {
- @@ -1688,28 +1743,92 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
- &motion_vector_vlc_table[0][1], 2, 1,
- &motion_vector_vlc_table[0][0], 2, 1, 0);
- - /* work out the block mapping tables */
- - s->superblock_fragments = av_malloc(s->superblock_count * 16 * sizeof(int));
- - s->macroblock_coding = av_malloc(s->macroblock_count + 1);
- - if (!s->superblock_fragments || !s->macroblock_coding) {
- - vp3_decode_end(avctx);
- - return -1;
- - }
- - init_block_mapping(s);
- -
- for (i = 0; i < 3; i++) {
- s->current_frame.data[i] = NULL;
- s->last_frame.data[i] = NULL;
- s->golden_frame.data[i] = NULL;
- }
- - return 0;
- + return allocate_tables(avctx);
- vlc_fail:
- av_log(avctx, AV_LOG_FATAL, "Invalid huffman table\n");
- return -1;
- }
- +/// Release and shuffle frames after decode finishes
- +static void update_frames(AVCodecContext *avctx)
- +{
- + Vp3DecodeContext *s = avctx->priv_data;
- +
- + /* release the last frame, if it is allocated and if it is not the
- + * golden frame */
- + if (s->last_frame.data[0] && s->last_frame.type != FF_BUFFER_TYPE_COPY)
- + ff_thread_release_buffer(avctx, &s->last_frame);
- +
- + /* shuffle frames (last = current) */
- + s->last_frame= s->current_frame;
- +
- + if (s->keyframe) {
- + if (s->golden_frame.data[0])
- + ff_thread_release_buffer(avctx, &s->golden_frame);
- + s->golden_frame = s->current_frame;
- + s->last_frame.type = FF_BUFFER_TYPE_COPY;
- + }
- +
- + s->current_frame.data[0]= NULL; /* ensure that we catch any access to this released frame */
- +}
- +
- +#define copy_fields(to, from, start_field, end_field) memcpy(&to->start_field, &from->start_field, (char*)&to->end_field - (char*)&to->start_field)
- +static int vp3_update_thread_context(AVCodecContext *dst, AVCodecContext *src)
- +{
- + Vp3DecodeContext *s = dst->priv_data, *s1 = src->priv_data;
- + int qps_changed = 0, i, err;
- +
- + if (!s1->current_frame.data[0]
- + ||s->width != s1->width
- + ||s->height!= s1->height)
- + return -1;
- +
- + if (s != s1) {
- + // init tables if the first frame hasn't been decoded
- + if (!s->current_frame.data[0]) {
- + int y_fragment_count, c_fragment_count;
- + s->avctx = dst;
- + err = allocate_tables(dst);
- + if (err)
- + return err;
- + y_fragment_count = s->fragment_width[0] * s->fragment_height[0];
- + c_fragment_count = s->fragment_width[1] * s->fragment_height[1];
- + memcpy(s->motion_val[0], s1->motion_val[0], y_fragment_count * sizeof(*s->motion_val[0]));
- + memcpy(s->motion_val[1], s1->motion_val[1], c_fragment_count * sizeof(*s->motion_val[1]));
- + }
- +
- + // copy previous frame data
- + copy_fields(s, s1, golden_frame, dsp);
- +
- + // copy qscale data if necessary
- + for (i = 0; i < 3; i++) {
- + if (s->qps[i] != s1->qps[1]) {
- + qps_changed = 1;
- + memcpy(&s->qmat[i], &s1->qmat[i], sizeof(s->qmat[i]));
- + }
- + }
- +
- + if (s->qps[0] != s1->qps[0]) {
- + memcpy(&s->qscale_table, &s1->qscale_table, sizeof(s->qscale_table));
- + memcpy(&s->bounding_values_array, &s1->bounding_values_array, sizeof(s->bounding_values_array));
- + }
- +
- + if (qps_changed)
- + copy_fields(s, s1, qps, superblock_count);
- + }
- +
- + update_frames(dst);
- +
- + return 0;
- +}
- +
- /*
- * This is the ffmpeg/libavcodec API frame decode function.
- */
- @@ -1721,7 +1840,6 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- int buf_size = avpkt->size;
- Vp3DecodeContext *s = avctx->priv_data;
- GetBitContext gb;
- - static int counter = 0;
- int i;
- init_get_bits(&gb, buf, buf_size * 8);
- @@ -1747,8 +1865,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_INFO, " VP3 %sframe #%d: Q index = %d\n",
- - s->keyframe?"key":"", counter, s->qps[0]);
- - counter++;
- + s->keyframe?"key":"", avctx->frame_number+1, s->qps[0]);
- s->skip_loop_filter = !s->filter_limit_values[s->qps[0]] ||
- avctx->skip_loop_filter >= (s->keyframe ? AVDISCARD_ALL : AVDISCARD_NONKEY);
- @@ -1767,7 +1884,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- s->current_frame.reference = 3;
- s->current_frame.pict_type = s->keyframe ? FF_I_TYPE : FF_P_TYPE;
- - if (avctx->get_buffer(avctx, &s->current_frame) < 0) {
- + if (ff_thread_get_buffer(avctx, &s->current_frame) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- goto error;
- }
- @@ -1780,7 +1897,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- if (s->version)
- {
- s->version = get_bits(&gb, 5);
- - if (counter == 1)
- + if (avctx->frame_number == 0)
- av_log(s->avctx, AV_LOG_DEBUG, "VP version: %d\n", s->version);
- }
- }
- @@ -1796,7 +1913,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- s->golden_frame.reference = 3;
- s->golden_frame.pict_type = FF_I_TYPE;
- - if (avctx->get_buffer(avctx, &s->golden_frame) < 0) {
- + if (ff_thread_get_buffer(avctx, &s->golden_frame) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- goto error;
- }
- @@ -1809,6 +1926,7 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- s->current_frame.qstride= 0;
- memset(s->all_fragments, 0, s->fragment_count * sizeof(Vp3Fragment));
- + ff_thread_finish_setup(avctx);
- if (unpack_superblocks(s, &gb)){
- av_log(s->avctx, AV_LOG_ERROR, "error in unpack_superblocks\n");
- @@ -1853,28 +1971,17 @@ static int vp3_decode_frame(AVCodecContext *avctx,
- *data_size=sizeof(AVFrame);
- *(AVFrame*)data= s->current_frame;
- - /* release the last frame, if it is allocated and if it is not the
- - * golden frame */
- - if (s->last_frame.data[0] && s->last_frame.type != FF_BUFFER_TYPE_COPY)
- - avctx->release_buffer(avctx, &s->last_frame);
- -
- - /* shuffle frames (last = current) */
- - s->last_frame= s->current_frame;
- -
- - if (s->keyframe) {
- - if (s->golden_frame.data[0])
- - avctx->release_buffer(avctx, &s->golden_frame);
- - s->golden_frame = s->current_frame;
- - s->last_frame.type = FF_BUFFER_TYPE_COPY;
- - }
- -
- - s->current_frame.data[0]= NULL; /* ensure that we catch any access to this released frame */
- + if (!HAVE_PTHREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME))
- + update_frames(avctx);
- return buf_size;
- error:
- - if (s->current_frame.data[0])
- + ff_thread_report_progress(&s->current_frame, INT_MAX, 0);
- +
- + if (!HAVE_PTHREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME))
- avctx->release_buffer(avctx, &s->current_frame);
- +
- return -1;
- }
- @@ -1886,6 +1993,9 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
- Vp3DecodeContext *s = avctx->priv_data;
- int i;
- + if (avctx->is_copy && !s->current_frame.data[0])
- + return 0;
- +
- av_free(s->superblock_coding);
- av_free(s->all_fragments);
- av_free(s->coded_fragment_list[0]);
- @@ -1895,6 +2005,8 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
- av_free(s->motion_val[0]);
- av_free(s->motion_val[1]);
- + if (avctx->is_copy) return 0;
- +
- for (i = 0; i < 16; i++) {
- free_vlc(&s->dc_vlc[i]);
- free_vlc(&s->ac_vlc_1[i]);
- @@ -1910,9 +2022,9 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
- /* release all frames */
- if (s->golden_frame.data[0])
- - avctx->release_buffer(avctx, &s->golden_frame);
- + ff_thread_release_buffer(avctx, &s->golden_frame);
- if (s->last_frame.data[0] && s->last_frame.type != FF_BUFFER_TYPE_COPY)
- - avctx->release_buffer(avctx, &s->last_frame);
- + ff_thread_release_buffer(avctx, &s->last_frame);
- /* no need to release the current_frame since it will always be pointing
- * to the same frame as either the golden or last frame */
- @@ -2227,9 +2339,10 @@ AVCodec theora_decoder = {
- NULL,
- vp3_decode_end,
- vp3_decode_frame,
- - CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND,
- + CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_FRAME_THREADS,
- NULL,
- .long_name = NULL_IF_CONFIG_SMALL("Theora"),
- + .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context)
- };
- #endif
- @@ -2242,7 +2355,8 @@ AVCodec vp3_decoder = {
- NULL,
- vp3_decode_end,
- vp3_decode_frame,
- - CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND,
- + CODEC_CAP_DR1 | CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_FRAME_THREADS,
- NULL,
- .long_name = NULL_IF_CONFIG_SMALL("On2 VP3"),
- + .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context)
- };
- diff --git a/libavcodec/w32thread.c b/libavcodec/w32thread.c
- index f7a1430..007508e 100644
- --- a/libavcodec/w32thread.c
- +++ b/libavcodec/w32thread.c
- @@ -129,7 +129,13 @@ int avcodec_thread_init(AVCodecContext *s, int thread_count){
- ThreadContext *c;
- uint32_t threadid;
- + if(!(s->thread_type & FF_THREAD_SLICE)){
- + av_log(s, AV_LOG_WARNING, "The requested thread algorithm is not supported with this thread library.\n");
- + return 0;
- + }
- +
- s->thread_count= thread_count;
- + s->active_thread_type= FF_THREAD_SLICE;
- if (thread_count <= 1)
- return 0;
- diff --git a/libavformat/utils.c b/libavformat/utils.c
- index 8a08557..16957e6 100644
- --- a/libavformat/utils.c
- +++ b/libavformat/utils.c
- @@ -909,6 +909,11 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
- /* do we have a video B-frame ? */
- delay= st->codec->has_b_frames;
- presentation_delayed = 0;
- +
- + // this delay should not count for undecoded frames
- + if (delay && st->codec->active_thread_type&FF_THREAD_FRAME)
- + delay -= st->codec->thread_count-1;
- +
- /* XXX: need has_b_frame, but cannot get it if the codec is
- not initialized */
- if (delay &&
- diff --git a/libavutil/internal.h b/libavutil/internal.h
- index 53d2b94..cc20ce7 100644
- --- a/libavutil/internal.h
- +++ b/libavutil/internal.h
- @@ -202,7 +202,6 @@
- # define NULL_IF_CONFIG_SMALL(x) x
- #endif
- -
- /**
- * Define a function with only the non-default version specified.
- *
- @@ -231,4 +230,15 @@
- type ff_##name args
- #endif
- +/**
- + * Returns NULL if a threading library has not been enabled.
- + * Used to disable threading functions in AVCodec definitions
- + * when not needed.
- + */
- +#if HAVE_THREADS
- +# define ONLY_IF_THREADS_ENABLED(x) x
- +#else
- +# define ONLY_IF_THREADS_ENABLED(x) NULL
- +#endif
- +
- #endif /* AVUTIL_INTERNAL_H */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement