]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/vp3.c
Use MAP_FAILED to check for mmap failure instead of manually
[ffmpeg] / libavcodec / vp3.c
index dbfacdc6f5acb5d7bd996820e211a38b1e796c5e..148f1179e3406f2c950f88c3edb7fa0d4c81108c 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include "libavcore/imgutils.h"
+#include "libavutil/imgutils.h"
 #include "avcodec.h"
 #include "dsputil.h"
 #include "get_bits.h"
 
 #include "vp3data.h"
 #include "xiph.h"
+#include "thread.h"
 
 #define FRAGMENT_PIXELS 8
 
@@ -236,8 +237,7 @@ typedef struct Vp3DecodeContext {
      * is coded. */
     unsigned char *macroblock_coding;
 
-    uint8_t edge_emu_buffer[9*2048]; //FIXME dynamic alloc
-    int8_t qscale_table[2048]; //FIXME dynamic alloc (width+15)/16
+    uint8_t *edge_emu_buffer;
 
     /* Huffman decode */
     int hti;
@@ -324,8 +324,6 @@ static void init_dequantizer(Vp3DecodeContext *s, int qpi)
             s->qmat[qpi][inter][plane][0] = s->qmat[0][inter][plane][0];
         }
     }
-
-    memset(s->qscale_table, (FFMAX(s->qmat[0][0][0][1], s->qmat[0][0][1][1])+8)/16, 512); //FIXME finetune
 }
 
 /*
@@ -1318,6 +1316,15 @@ 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;
+
+        // At the end of the frame, report INT_MAX instead of the height of the frame.
+        // This makes the other threads' ff_thread_await_progress() calls cheaper, because
+        // they don't have to clip their values.
+        ff_thread_report_progress(&s->current_frame, y_flipped==s->avctx->height ? INT_MAX : y_flipped-1, 0);
+    }
+
     if(s->avctx->draw_horiz_band==NULL)
         return;
 
@@ -1339,6 +1346,28 @@ 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 the current fragment.
+ * The progress value is in luma pixel rows.
+ */
+static void await_reference_row(Vp3DecodeContext *s, Vp3Fragment *fragment, int motion_y, int y)
+{
+    AVFrame *ref_frame;
+    int ref_row;
+    int border = motion_y&1;
+
+    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, ref_row, 0);
+}
+
 /*
  * Perform the final rendering for a particular slice of data.
  * The slice number ranges from 0..(c_superblock_height - 1).
@@ -1371,15 +1400,12 @@ static void render_slice(Vp3DecodeContext *s, int slice)
         int fragment_width    = s->fragment_width[!!plane];
         int fragment_height   = s->fragment_height[!!plane];
         int fragment_start    = s->fragment_start[plane];
+        int do_await          = !plane && HAVE_PTHREADS && (s->avctx->active_thread_type&FF_THREAD_FRAME);
 
         if (!s->flipped_image) stride = -stride;
         if (CONFIG_GRAY && plane && (s->avctx->flags & CODEC_FLAG_GRAY))
             continue;
 
-
-        if(FFABS(stride) > 2048)
-            return; //various tables are fixed size
-
         /* for each superblock row in the slice (both of them)... */
         for (; sb_y < slice_height; sb_y++) {
 
@@ -1400,6 +1426,9 @@ static void render_slice(Vp3DecodeContext *s, int slice)
 
                 first_pixel = 8*y*stride + 8*x;
 
+                if (do_await && s->all_fragments[i].coding_method != MODE_INTRA)
+                    await_reference_row(s, &s->all_fragments[i], motion_val[fragment][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) ||
@@ -1430,8 +1459,7 @@ static void render_slice(Vp3DecodeContext *s, int slice)
 
                         if(src_x<0 || src_y<0 || src_x + 9 >= plane_width || src_y + 9 >= plane_height){
                             uint8_t *temp= s->edge_emu_buffer;
-                            if(stride<0) temp -= 9*stride;
-                            else temp += 9*stride;
+                            if(stride<0) temp -= 8*stride;
 
                             s->dsp.emulated_edge_mc(temp, motion_source, stride, 9, 9, src_x, src_y, plane_width, plane_height);
                             motion_source= temp;
@@ -1721,6 +1749,79 @@ vlc_fail:
     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 */
+}
+
+static int vp3_update_thread_context(AVCodecContext *dst, const 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]));
+        }
+
+#define copy_fields(to, from, start_field, end_field) memcpy(&to->start_field, &from->start_field, (char*)&to->end_field - (char*)&to->start_field)
+
+        // 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->bounding_values_array, &s1->bounding_values_array, sizeof(s->bounding_values_array));
+
+        if (qps_changed)
+            copy_fields(s, s1, qps, superblock_count);
+#undef copy_fields
+    }
+
+    update_frames(dst);
+
+    return 0;
+}
+
 /*
  * This is the ffmpeg/libavcodec API frame decode function.
  */
@@ -1775,12 +1876,15 @@ static int vp3_decode_frame(AVCodecContext *avctx,
         return buf_size;
 
     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) {
+    s->current_frame.pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+    if (ff_thread_get_buffer(avctx, &s->current_frame) < 0) {
         av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         goto error;
     }
 
+    if (!s->edge_emu_buffer)
+        s->edge_emu_buffer = av_malloc(9*FFABS(s->current_frame.linesize[0]));
+
     if (s->keyframe) {
         if (!s->theora)
         {
@@ -1804,20 +1908,19 @@ static int vp3_decode_frame(AVCodecContext *avctx,
             av_log(s->avctx, AV_LOG_WARNING, "vp3: first frame not a keyframe\n");
 
             s->golden_frame.reference = 3;
-            s->golden_frame.pict_type = FF_I_TYPE;
-            if (avctx->get_buffer(avctx, &s->golden_frame) < 0) {
+            s->golden_frame.pict_type = AV_PICTURE_TYPE_I;
+            if (ff_thread_get_buffer(avctx, &s->golden_frame) < 0) {
                 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
                 goto error;
             }
             s->last_frame = s->golden_frame;
             s->last_frame.type = FF_BUFFER_TYPE_COPY;
+            ff_thread_report_progress(&s->last_frame, INT_MAX, 0);
         }
     }
 
-    s->current_frame.qscale_table= s->qscale_table; //FIXME allocate individual tables per AVFrame
-    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");
@@ -1862,28 +1965,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;
 }
 
@@ -1895,6 +1987,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]);
@@ -1903,6 +1998,9 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
     av_free(s->macroblock_coding);
     av_free(s->motion_val[0]);
     av_free(s->motion_val[1]);
+    av_free(s->edge_emu_buffer);
+
+    if (avctx->is_copy) return 0;
 
     for (i = 0; i < 16; i++) {
         free_vlc(&s->dc_vlc[i]);
@@ -1919,9 +2017,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 */
 
@@ -2232,9 +2330,10 @@ AVCodec ff_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
 
@@ -2247,7 +2346,8 @@ AVCodec ff_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)
 };