implementing more efficient (and direct) allocation of work for DV codec workers
authorRoman Shaposhnik <roman@shaposhnik.org>
Sat, 8 Nov 2008 00:18:00 +0000 (00:18 +0000)
committerRoman Shaposhnik <roman@shaposhnik.org>
Sat, 8 Nov 2008 00:18:00 +0000 (00:18 +0000)
Originally committed as revision 15788 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/dv.c
libavcodec/dvdata.h

index f208fd9..8dec537 100644 (file)
@@ -62,15 +62,6 @@ typedef struct DVVideoContext {
     void (*idct_put[2])(uint8_t *dest, int line_size, DCTELEM *block);
 } DVVideoContext;
 
-/**
- * MultiThreading - dv_anchor applies to entire DV codec, not just the avcontext
- * one element is needed for each video segment in a DV frame
- * at most there are 4 DIF channels * 12 DIF sequences * 27 video segments (1080i50)
- */
-#define DV_ANCHOR_SIZE (4*12*27)
-
-static void* dv_anchor[DV_ANCHOR_SIZE];
-
 #define TEX_VLC_BITS 9
 
 #if ENABLE_SMALL
@@ -89,6 +80,40 @@ static struct dv_vlc_pair {
    uint8_t  size;
 } dv_vlc_map[DV_VLC_MAP_RUN_SIZE][DV_VLC_MAP_LEV_SIZE];
 
+static inline int dv_work_pool_size(const DVprofile *d)
+{
+    int size = d->n_difchan*d->difseg_size*27;
+    if (DV_PROFILE_IS_1080i50(d))
+        size -= 3*27;
+    if (DV_PROFILE_IS_720p50(d))
+        size -= 4*27;
+    return size;
+}
+
+static int dv_init_dynamic_tables(const DVprofile *d)
+{
+    int j,i,c,s,p;
+
+    if (d->work_chunks[dv_work_pool_size(d)-1])
+        return 0;
+
+    p = i = 0;
+    for (c=0; c<d->n_difchan; c++) {
+        for (s=0; s<d->difseg_size; s++) {
+            p += 6;
+            for (j=0; j<27; j++) {
+                 p += !(j%3);
+                 if (!(DV_PROFILE_IS_1080i50(d) && c != 0 && s == 11) &&
+                     !(DV_PROFILE_IS_720p50(d) && s > 9)) {
+                     d->work_chunks[i++] = (void*)(size_t)((p<<18)|(c << 16)|(s << 8)|j);
+                 }
+                 p += 5;
+            }
+        }
+    }
+    return 0;
+}
+
 static void dv_build_unquantize_tables(DVVideoContext *s, uint8_t* perm)
 {
     int i, q, a;
@@ -138,10 +163,6 @@ static av_cold int dvvideo_init(AVCodecContext *avctx)
 
         done = 1;
 
-        /* dv_anchor lets each thread know its ID */
-        for (i = 0; i < DV_ANCHOR_SIZE; i++)
-            dv_anchor[i] = (void*)(size_t)i;
-
         /* it's faster to include sign bit in a generic VLC parsing scheme */
         for (i = 0, j = 0; i < NB_DV_VLC; i++, j++) {
             new_dv_vlc_bits[j]  = dv_vlc_bits[i];
@@ -360,13 +381,29 @@ static inline void bit_copy(PutBitContext *pb, GetBitContext *gb)
     }
 }
 
+static inline void dv_calculate_mb_xy(DVVideoContext *s, int work_chunk, int m, int *mb_x, int *mb_y)
+{
+     int i, chan, seg, slot;
+
+     chan = (work_chunk>>16)&0x03;
+     seg  = (work_chunk>>8)&0xff;
+     slot = (work_chunk)&0xff;
+
+     i = (chan*s->sys->difseg_size+seg)*27*5 + slot*5 + m;
+     *mb_x = s->sys->video_place[i] & 0xff;
+     *mb_y = s->sys->video_place[i] >> 8;
+
+     /* We work with 720p frames split in half. The odd half-frame (chan==2,3) is displaced :-( */
+     if (s->sys->height == 720 && !(s->buf[1]&0x0C)) {
+         *mb_y -= (*mb_y>17)?18:-72; /* shifting the Y coordinate down by 72/2 macro blocks */
+     }
+}
+
 /* mb_x and mb_y are in units of 8 pixels */
-static inline void dv_decode_video_segment(DVVideoContext *s,
-                                           const uint8_t  *buf_ptr1,
-                                           const uint16_t *mb_pos_ptr)
+static inline void dv_decode_video_segment(DVVideoContext *s, int work_chunk)
 {
     int quant, dc, dct_mode, class1, j;
-    int mb_index, mb_x, mb_y, v, last_index;
+    int mb_index, mb_x, mb_y, last_index;
     int y_stride, linesize;
     DCTELEM *block, *block1;
     int c_offset;
@@ -387,7 +424,7 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
     memset(sblock, 0, sizeof(sblock));
 
     /* pass 1 : read DC and AC coefficients in blocks */
-    buf_ptr = buf_ptr1;
+    buf_ptr = &s->buf[(work_chunk>>18)*80];
     block1  = &sblock[0][0];
     mb1     = mb_data;
     init_put_bits(&vs_pb, vs_bit_buffer, 5 * 80);
@@ -490,13 +527,7 @@ static inline void dv_decode_video_segment(DVVideoContext *s,
     block = &sblock[0][0];
     mb    = mb_data;
     for (mb_index = 0; mb_index < 5; mb_index++) {
-        v = *mb_pos_ptr++;
-        mb_x = v & 0xff;
-        mb_y = v >> 8;
-        /* We work with 720p frames split in half. The odd half-frame (chan==2,3) is displaced :-( */
-        if (s->sys->height == 720 && !(s->buf[1] & 0x0C)) {
-               mb_y -= (mb_y > 17) ? 18 : -72; /* shifting the Y coordinate down by 72/2 macroblocks */
-        }
+        dv_calculate_mb_xy(s, work_chunk, mb_index, &mb_x, &mb_y);
 
         /* idct_put'ting luminance */
         if ((s->sys->pix_fmt == PIX_FMT_YUV420P) ||
@@ -831,15 +862,14 @@ static inline void dv_guess_qnos(EncBlockInfo* blks, int* qnos)
     }
 }
 
-static inline void dv_encode_video_segment(DVVideoContext *s,
-                                           uint8_t *dif,
-                                           const uint16_t *mb_pos_ptr)
+static inline void dv_encode_video_segment(DVVideoContext *s, int work_chunk)
 {
-    int mb_index, i, j, v;
+    int mb_index, i, j;
     int mb_x, mb_y, c_offset, linesize;
     uint8_t*  y_ptr;
     uint8_t*  data;
     uint8_t*  ptr;
+    uint8_t*  dif;
     int       do_edge_wrap;
     DECLARE_ALIGNED_16(DCTELEM, block[64]);
     EncBlockInfo  enc_blks[5*6];
@@ -851,12 +881,11 @@ static inline void dv_encode_video_segment(DVVideoContext *s,
 
     assert((((int)block) & 15) == 0);
 
+    dif = &s->buf[(work_chunk>>18)*80];
     enc_blk = &enc_blks[0];
     pb = &pbs[0];
     for (mb_index = 0; mb_index < 5; mb_index++) {
-        v        = *mb_pos_ptr++;
-        mb_x     = v & 0xff;
-        mb_y     = v >> 8;
+        dv_calculate_mb_xy(s, work_chunk, mb_index, &mb_x, &mb_y);
         y_ptr    = s->picture.data[0] + ((mb_y * s->picture.linesize[0] + mb_x) << 3);
         c_offset = (((mb_y >>  (s->sys->pix_fmt == PIX_FMT_YUV420P)) * s->picture.linesize[1] +
                      (mb_x >> ((s->sys->pix_fmt == PIX_FMT_YUV411P) ? 2 : 1))) << 3);
@@ -984,52 +1013,14 @@ static inline void dv_encode_video_segment(DVVideoContext *s,
 
 static int dv_decode_mt(AVCodecContext *avctx, void* sl)
 {
-    DVVideoContext *s = avctx->priv_data;
-    int slice = (size_t)sl;
-
-    /* which DIF channel is this? */
-    int chan = slice / (s->sys->difseg_size * 27);
-
-    /* slice within the DIF channel */
-    int chan_slice = slice % (s->sys->difseg_size * 27);
-
-    /* byte offset of this channel's data */
-    int chan_offset = chan * s->sys->difseg_size * 150 * 80;
-
-    /* DIF sequence */
-    int seq = chan_slice / 27;
-
-    /* in 1080i50 and 720p50 some seq are unused */
-    if ((DV_PROFILE_IS_1080i50(s->sys) && chan != 0 && seq == 11) ||
-        (DV_PROFILE_IS_720p50(s->sys) && seq > 9))
-        return 0;
-
-    dv_decode_video_segment(s, &s->buf[(seq * 6 + (chan_slice / 3)
-                                        + chan_slice * 5 + 7)
-                                       * 80 + chan_offset],
-                            &s->sys->video_place[slice * 5]);
+    dv_decode_video_segment((DVVideoContext *)avctx->priv_data, (size_t)sl);
     return 0;
 }
 
 #ifdef CONFIG_DVVIDEO_ENCODER
 static int dv_encode_mt(AVCodecContext *avctx, void* sl)
 {
-    DVVideoContext *s = avctx->priv_data;
-    int slice = (size_t)sl;
-
-    /* which DIF channel is this? */
-    int chan = slice / (s->sys->difseg_size * 27);
-
-    /* slice within the DIF channel */
-    int chan_slice = slice % (s->sys->difseg_size * 27);
-
-    /* byte offset of this channel's data */
-    int chan_offset = chan * s->sys->difseg_size * 150 * 80;
-
-    dv_encode_video_segment(s, &s->buf[((chan_slice / 27) * 6 + (chan_slice / 3)
-                                         + chan_slice * 5 + 7)
-                                       * 80 + chan_offset],
-                            &s->sys->video_place[slice * 5]);
+    dv_encode_video_segment((DVVideoContext *)avctx->priv_data, (size_t)sl);
     return 0;
 }
 #endif
@@ -1044,7 +1035,7 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
     DVVideoContext *s = avctx->priv_data;
 
     s->sys = dv_frame_profile(buf);
-    if (!s->sys || buf_size < s->sys->frame_size)
+    if (!s->sys || buf_size < s->sys->frame_size || dv_init_dynamic_tables(s->sys))
         return -1; /* NOTE: we only accept several full frames */
 
     if (s->picture.data[0])
@@ -1064,8 +1055,8 @@ static int dvvideo_decode_frame(AVCodecContext *avctx,
     s->picture.top_field_first  = 0;
 
     s->buf = buf;
-    avctx->execute(avctx, dv_decode_mt, (void**)&dv_anchor[0], NULL,
-                   s->sys->n_difchan * s->sys->difseg_size * 27);
+    avctx->execute(avctx, dv_decode_mt, s->sys->work_chunks, NULL,
+                   dv_work_pool_size(s->sys));
 
     emms_c();
 
@@ -1208,9 +1199,7 @@ static int dvvideo_encode_frame(AVCodecContext *c, uint8_t *buf, int buf_size,
     DVVideoContext *s = c->priv_data;
 
     s->sys = dv_codec_profile(c);
-    if (!s->sys)
-        return -1;
-    if (buf_size < s->sys->frame_size)
+    if (!s->sys || buf_size < s->sys->frame_size || dv_init_dynamic_tables(s->sys))
         return -1;
 
     c->pix_fmt           = s->sys->pix_fmt;
@@ -1219,8 +1208,8 @@ static int dvvideo_encode_frame(AVCodecContext *c, uint8_t *buf, int buf_size,
     s->picture.pict_type = FF_I_TYPE;
 
     s->buf = buf;
-    c->execute(c, dv_encode_mt, (void**)&dv_anchor[0], NULL,
-               s->sys->n_difchan * s->sys->difseg_size * 27);
+    c->execute(c, dv_encode_mt, s->sys->work_chunks, NULL,
+               dv_work_pool_size(s->sys));
 
     emms_c();
 
index e762c41..0e4381c 100644 (file)
@@ -47,6 +47,7 @@ typedef struct DVprofile {
     int              height;                /* picture height in pixels */
     int              width;                 /* picture width in pixels */
     AVRational       sar[2];                /* sample aspect ratios for 4:3 and 16:9 */
+    void           **work_chunks;           /* each thread gets its own chunk of frame to work on */
     const uint16_t  *video_place;           /* positions of all DV macroblocks */
     enum PixelFormat pix_fmt;               /* picture pixel format */
     int              bpm;                   /* blocks per macroblock */
@@ -6159,6 +6160,16 @@ static const uint8_t block_sizes_dv100[8] = {
     80, 80, 80, 80, 80, 80, 64, 64,
 };
 
+static void  *work_chunks_dv25pal   [1*12*27];
+static void  *work_chunks_dv25pal411[1*12*27];
+static void  *work_chunks_dv25ntsc  [1*10*27];
+static void  *work_chunks_dv50pal   [2*12*27];
+static void  *work_chunks_dv50ntsc  [2*10*27];
+static void  *work_chunks_dv100palp [2*12*27];
+static void  *work_chunks_dv100ntscp[2*10*27];
+static void  *work_chunks_dv100pali [4*12*27];
+static void  *work_chunks_dv100ntsci[4*10*27];
+
 static const DVprofile dv_profiles[] = {
     { .dsf = 0,
       .video_stype = 0x0,
@@ -6171,6 +6182,7 @@ static const DVprofile dv_profiles[] = {
       .width = 720,
       .sar = {{10, 11}, {40, 33}},
       .video_place = dv_place_411,
+      .work_chunks = &work_chunks_dv25ntsc[0],
       .pix_fmt = PIX_FMT_YUV411P,
       .bpm = 6,
       .block_sizes = block_sizes_dv2550,
@@ -6190,6 +6202,7 @@ static const DVprofile dv_profiles[] = {
       .width = 720,
       .sar = {{59, 54}, {118, 81}},
       .video_place = dv_place_420,
+      .work_chunks = &work_chunks_dv25pal[0],
       .pix_fmt = PIX_FMT_YUV420P,
       .bpm = 6,
       .block_sizes = block_sizes_dv2550,
@@ -6209,6 +6222,7 @@ static const DVprofile dv_profiles[] = {
       .width = 720,
       .sar = {{59, 54}, {118, 81}},
       .video_place = dv_place_411P,
+      .work_chunks = &work_chunks_dv25pal411[0],
       .pix_fmt = PIX_FMT_YUV411P,
       .bpm = 6,
       .block_sizes = block_sizes_dv2550,
@@ -6228,6 +6242,7 @@ static const DVprofile dv_profiles[] = {
       .width = 720,
       .sar = {{10, 11}, {40, 33}},
       .video_place = dv_place_422_525,
+      .work_chunks = &work_chunks_dv50ntsc[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 6,
       .block_sizes = block_sizes_dv2550,
@@ -6247,6 +6262,7 @@ static const DVprofile dv_profiles[] = {
       .width = 720,
       .sar = {{59, 54}, {118, 81}},
       .video_place = dv_place_422_625,
+      .work_chunks = &work_chunks_dv50pal[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 6,
       .block_sizes = block_sizes_dv2550,
@@ -6266,6 +6282,7 @@ static const DVprofile dv_profiles[] = {
       .width = 1280,
       .sar = {{1, 1}, {1, 1}},
       .video_place = dv_place_1080i60,
+      .work_chunks = &work_chunks_dv100ntsci[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 8,
       .block_sizes = block_sizes_dv100,
@@ -6285,6 +6302,7 @@ static const DVprofile dv_profiles[] = {
       .width = 1440,
       .sar = {{1, 1}, {1, 1}},
       .video_place = dv_place_1080i50,
+      .work_chunks = &work_chunks_dv100pali[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 8,
       .block_sizes = block_sizes_dv100,
@@ -6304,6 +6322,7 @@ static const DVprofile dv_profiles[] = {
       .width = 960,
       .sar = {{1, 1}, {1, 1}},
       .video_place = dv_place_720p60,
+      .work_chunks = &work_chunks_dv100ntscp[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 8,
       .block_sizes = block_sizes_dv100,
@@ -6323,6 +6342,7 @@ static const DVprofile dv_profiles[] = {
       .width = 960,
       .sar = {{1, 1}, {1, 1}},
       .video_place = dv_place_720p50,
+      .work_chunks = &work_chunks_dv100palp[0],
       .pix_fmt = PIX_FMT_YUV422P,
       .bpm = 8,
       .block_sizes = block_sizes_dv100,