[FFmpeg-devel] [PATCH][RFC] Indeo3 replacement
Michael Niedermayer
michaelni
Mon Jul 27 11:02:05 CEST 2009
On Sun, Jul 26, 2009 at 11:16:22PM +0200, Maxim wrote:
> Michael Niedermayer schrieb:
> > [...]
> >> /* FIXME: I know we already have a bitreader in ffmpeg */
> >> /* it should be adapted to read ahead only one byte */
> >> /* otherwise it won't work for indeo3 !!! */
> >>
> >
> > elaborate please
> >
>
> Ok, frame data mixes binary tree which is a bitstream with cell data
> which is a bytestream.
> Below an example of a typical parsing sequence.
> Consider the following frame data:
>
> Addr
> 0000 0x11,
> 0001 0x6C,
> 0002 0x0,
> 0003 0x1,
> 0004 0xFD,
> 0005 0xFB,
> 0006 0x3,
> 0007 0x11
>
> We parse them as follows:
>
> data_ptr points to the next data code
> read_bintree_code() reads 2bit codes starting with MSB
>
> bs_cache = *data_ptr++; // feed the bitstream reader with the first byte
> = 0x11 = %00010001
> code = read_bintree_code(); // we'll get %00 = H_SPLIT, bs_cache = %010001
> ...process this code...
> code = read_bintree_code(); // we'll get %01 = V_SPLIT, bs_cache = %0001
> ...process this code...
> code = read_bintree_code(); // we'll get %00 = H_SPLIT, bs_cache = %01
> ...process this code...
> code = read_bintree_code(); // we'll get %01 = V_SPLIT, bs_cache = empty
> bs_cache = *data_ptr++; // feed the bitstream reader with the 2nd byte =
> 0x6C = %01101100
> ...process "code"...
> code = read_bintree_code(); // we'll get %01 = V_SPLIT, bs_cache = %101100
> ...process this code...
> code = read_bintree_code(); // we'll get %10 = INTRA, bs_cache = %1100
> ...process this code...
> code = read_bintree_code(); // we'll get %11 = VQ_DATA, bs_cache = %00
>
> at this place we call decode_cell() routine that takes the data_ptr
> pointed to the cell data starting with the address 0002. The data at
> this position is treated as bytestream now. After cell decoding we set
> the data_ptr to the next byte.
>
> data_ptr = decode_cell(data_ptr);
>
> // data_ptr points to addr 0007 now
>
> code = read_bintree_code(); // we'll get %00 = H_SPLIT, bs_cache = empty
> bs_cache = *data_ptr++; // feed the bitstream reader with the 7th byte =
> 0x11 = %00010001
>
> ... continue processing...
>
> So, the code needs to manipulate the internal structs of the FFmpeg's
> bitreader in order to achieve the same behaviour what's not really safe
> IMHO. Maybe there is a possibility to do it smart. I don't know...
i dont see why you would have to mess with internal structs to switch betweem
byte & bit reading
>
>
> > [...]
> >
> >
> >> prim_delta = &delta_tabs [prim_indx] [0];
> >> prim_sel = &selector_tabs[prim_indx] [0];
> >> second_delta = &delta_tabs [second_indx][0];
> >> second_sel = &selector_tabs[second_indx][0];
> >> } else {
> >> vq_index += ctx->cb_offset;
> >> assert(vq_index <= 23);
> >>
> >> prim_delta = &delta_tabs [vq_index][0];
> >> prim_sel = &selector_tabs[vq_index][0];
> >> second_delta = prim_delta;
> >> second_sel = prim_sel;
> >> }
> >>
> >> /* requantize the prediction if VQ index of this cell differs from VQ index */
> >> /* of the predicted cell in order to avoid overflows. */
> >> /* FIXME: if (vq_index >= 8 && (mode == 0 || mode == 3 || mode == 10) [win32] */
> >> if (vq_index >= 8) {
> >> for (x = 0; x < cell->width << 2; x++)
> >> ref_block[x] = requant_tab[vq_index & 7][ref_block[x]];
> >> }
> >>
> >> /* convert the pixel offset into 4x4 block one */
> >> row_offset = plane->pitch >> 2;
> >> blk_row_offset = (plane->pitch - cell->width) << 2;
> >>
> >> rle_blocks = 0; // reset RLE block counter
> >>
> >> switch (mode) {
> >> case 0: /*------------------ MODES 0 & 1 (4x4 block processing) --------------------*/
> >> case 1:
> >> skip_flag = 0;
> >>
> >> for (y = 0; y < cell->height; y++) {
> >> for (x = 0; x < cell->width; x++) {
> >> /* address 4 pixels as one 32bit integer */
> >> ref32 = (int32_t *)ref_block;
> >> src32 = (int32_t *)block;
> >>
> >> if (rle_blocks > 0) {
> >> /* apply 0 delta to whole next block */
> >> if (cell->mv_ptr || !skip_flag)
> >> copy_32(src32, ref32, 4, row_offset);
> >> rle_blocks--;
> >> } else {
> >> for (line = 0; line < 4;) {
> >> num_lines = 1;
> >>
> >> code = *data_ptr++;
> >> /* select primary VQ table for odd, secondary for even lines */
> >> delta_tab = (line & 1) ? prim_delta : second_delta;
> >>
> >> /* switch on code type: dyad, quad or RLE escape codes */
> >> switch ((line & 1) ? prim_sel[code] : second_sel[code]) {
> >> case DELTA_DYAD: /* apply VQ delta to two dyads (2+2 pixels) using softSIMD */
> >> if (((line & 1) ? prim_sel[*data_ptr] : second_sel[*data_ptr]) != DELTA_DYAD) {
> >> av_log(avctx, AV_LOG_ERROR, "Mode 0/1: invalid VQ data!\n");
> >> return -1;
> >> }
> >> ref16 = (int16_t *)ref32;
> >> src16 = (int16_t *)src32;
> >> src16[0] = ref16[0] + delta_tab[*data_ptr++];
> >> src16[1] = ref16[1] + delta_tab[code];
> >> break;
> >>
> >> case DELTA_QUAD: /* apply VQ delta to 4 pixels at once using softSIMD */
> >> src32[0] = ref32[0] + delta_tab[code];
> >> break;
> >>
> >> case RLE_ESC_FF: /* apply null delta to all lines up to the 2nd line */
> >> //assert(line < 1);
> >> copy_32(src32, ref32, 2, row_offset);
> >> num_lines = 2;
> >> break;
> >>
> >> case RLE_ESC_FE: /* apply null delta to all lines up to the 3rd line */
> >> //assert(line < 2);
> >> copy_32(src32, ref32, 3 - line, row_offset);
> >> num_lines = 3 - line;
> >> break;
> >>
> >> case RLE_ESC_FC:
> >> /* apply null delta to all remaining lines of this block
> >> and to whole next block */
> >> skip_flag = 0;
> >> rle_blocks = 1;
> >>
> >> case RLE_ESC_FD: /* apply null delta to all remaining lines of this block */
> >> copy_32(src32, ref32, 4 - line, row_offset);
> >> num_lines = 4 - line; /* go to process next block */
> >> break;
> >>
> >> case RLE_ESC_FB: /* apply null delta to n blocks/skip n blocks */
> >> /* get next byte after the escape code 0xFB */
> >> code = *data_ptr++;
> >> rle_blocks = (code & 0x1F) - 1; /* set the block counter */
> >> if (code >= 64 || rle_blocks < 0) {
> >> av_log(avctx, AV_LOG_ERROR, "Mode 0/1: RLE-FB invalid counter: %d!\n", code);
> >> return -1;
> >> }
> >> skip_flag = code & 0x20;
> >> if (cell->mv_ptr || !skip_flag)
> >> copy_32(src32, ref32, 4 - line, row_offset);
> >> num_lines = 4 - line; /* go to process next block */
> >> break;
> >>
> >> case RLE_ESC_F9: /* skip this block and the next one */
> >> skip_flag = 1;
> >> rle_blocks = 1;
> >>
> >> case RLE_ESC_FA: /* skip this block (INTRA) or copy the reference block (INTER) */
> >> assert(!line);
> >> if (cell->mv_ptr)
> >> copy_32(src32, ref32, 4, row_offset);
> >> num_lines = 4;
> >> break;
> >>
> >> default:
> >> av_log(avctx, AV_LOG_ERROR, "Mode 0/1: unsupported RLE code: %d!\n",
> >> (line & 1) ? prim_sel[code] : second_sel[code]);
> >> return(-1);
> >> }// switch code
> >>
> >> /* move forward num_lines */
> >> line += num_lines;
> >> ref32 += row_offset * num_lines;
> >> src32 += row_offset * num_lines;
> >> }// for line
> >> }// if/else
> >>
> >> /* move to next block horizontal */
> >> ref_block += 4;
> >> block += 4;
> >> }// for x
> >>
> >> /* move to next line of blocks */
> >> ref_block += blk_row_offset;
> >> block += blk_row_offset;
> >> }// for y
> >> break;
> >>
> >> case 3: /*------------------ MODES 3 & 4 (4x8 block processing) --------------------*/
> >> case 4:
> >> if (cell->mv_ptr) {
> >> av_log(avctx, AV_LOG_ERROR, "Trying to use Mode 3/4 for an INTER cell!\n");
> >> return -1;
> >> }
> >> block32 = (int32_t *)block;
> >> blk_row_offset = (row_offset << 3) - cell->width;
> >> skip_flag = 0;
> >>
> >> for (y = 0, is_first_row = 1; y < cell->height; y += 2) {
> >> for (x = 0; x < cell->width; x++) {
> >> /* address 4 pixels as one 32bit integer */
> >> ref32 = &block32[-row_offset];
> >> src32 = &block32[row_offset];
> >>
> >> if (rle_blocks > 0) {
> >> /* apply 0 delta to whole next block */
> >> if (!skip_flag)
> >> copy_32(block32, ref32, 8, row_offset);
> >> rle_blocks--;
> >> } else {
> >> for(line = 0; line < 4;) {
> >> num_lines = 1;
> >> is_top_of_cell = is_first_row & (!line);
> >>
> >> code = *data_ptr++;
> >> /* select primary VQ table for odd, secondary for even lines */
> >> delta_tab = (line & 1) ? prim_delta : second_delta;
> >>
> >> /* switch on code type: dyad, quad or RLE escape codes */
> >> switch ((line & 1) ? prim_sel[code] : second_sel[code]) {
> >> case DELTA_DYAD: /* apply VQ delta to two dyads (2+2 pixels) using softSIMD */
> >> if (((line & 1) ? prim_sel[*data_ptr] : second_sel[*data_ptr]) != DELTA_DYAD) {
> >> av_log(avctx, AV_LOG_ERROR, "Mode 3/4: invalid VQ data!\n");
> >> return -1;
> >> }
> >> ref16 = (int16_t *)ref32;
> >> src16 = (int16_t *)src32;
> >> src16[0] = ref16[0] + delta_tab[*data_ptr++];
> >> src16[1] = ref16[1] + delta_tab[code];
> >>
> >> /* odd lines are not coded but rather interpolated/replicated */
> >> /* first line of the cell on the top of image? - replicate */
> >> /* otherwise - interpolate */
> >> if (is_top_of_cell && !cell->ypos) {
> >> src32[-row_offset] = src32[0];
> >> } else
> >> INTERPOLATE_32(src32 -row_offset, src32, ref32);
> >> break;
> >>
> >> case DELTA_QUAD: /* apply VQ delta to 4 pixels at once using softSIMD */
> >> src32[0] = ref32[0] + delta_tab[code];
> >> if (is_top_of_cell && !cell->ypos) {
> >> src32[-row_offset] = src32[0];
> >> } else
> >> INTERPOLATE_32(src32 -row_offset, src32, ref32);
> >> break;
> >>
> >> case RLE_ESC_FF: /* apply null delta to all lines up to the 2nd line */
> >> assert(line < 1);
> >> copy_32(src32 - row_offset, ref32, 4, row_offset);
> >> num_lines = 2;
> >> break;
> >>
> >> case RLE_ESC_FE: /* apply null delta to all lines up to the 3rd line */
> >> assert(line < 2);
> >> copy_32(src32 - row_offset, ref32, (3 - line) << 1, row_offset);
> >> num_lines = 3 - line;
> >> break;
> >>
> >> case RLE_ESC_FC:
> >> /* apply null delta to all remaining lines of this block
> >> and to whole next block */
> >> skip_flag = 0;
> >> rle_blocks = 1;
> >>
> >> case RLE_ESC_FD: /* apply null delta to all remaining lines of this block */
> >> copy_32(src32 - row_offset, ref32, (4 - line) << 1, row_offset);
> >> num_lines = 4 - line; /* go to process next block */
> >> break;
> >>
> >> case RLE_ESC_FB: /* apply null delta to n blocks/skip n blocks */
> >> /* get next byte after the escape code 0xFB */
> >> code = *data_ptr++;
> >> rle_blocks = (code & 0x1F) - 1; /* set the block counter */
> >> if (code >= 64 || rle_blocks < 0) {
> >> av_log(avctx, AV_LOG_ERROR, "Mode 3/4: RLE-FB invalid counter: %d!\n", code);
> >> return -1;
> >> }
> >> skip_flag = code & 0x20;
> >> if (!skip_flag)
> >> copy_32(src32 - row_offset, ref32, (4 - line) << 1, row_offset);
> >> num_lines = 4 - line; /* go to process next block */
> >> break;
> >>
> >> case RLE_ESC_F9: /* skip this block and the next one */
> >> skip_flag = 1;
> >> rle_blocks = 1;
> >>
> >> case RLE_ESC_FA: /* skip this block */
> >> assert(!line);
> >> num_lines = 4;
> >> break;
> >>
> >> default:
> >> av_log(avctx, AV_LOG_ERROR, "Mode 3/4: unsupported RLE code: %d!\n",
> >> (line & 1) ? prim_sel[code] : second_sel[code]);
> >> return(-1);
> >> }// switch code
> >>
> >> /* move to num_lines (even) */
> >> line += num_lines;
> >> ref32 += row_offset * (num_lines << 1);
> >> src32 += row_offset * (num_lines << 1);
> >> }// for line
> >> }// if/else
> >>
> >> /* move to next block horizontal */
> >> block32++;
> >> }// for x
> >>
> >> /* move to next line of blocks */
> >> block32 += blk_row_offset;
> >> is_first_row = 0;
> >> }// for y
> >> break;
> >>
> >
> > looks very similar to the 4x4 code ...
> >
>
> Yes, it looks similar but these actually aren't the same... Modes 3/4
> process twice as many lines than the mode 0/1. Fix me when I'm wrong but
add a variable that represents the num of lines and use it ...
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Those who are too smart to engage in politics are punished by being
governed by those who are dumber. -- Plato
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090727/6af9538e/attachment.pgp>
More information about the ffmpeg-devel
mailing list