[XviD-devel] trying to introduce resync markers

sigdrak sigdrak at free.fr
Sun May 15 15:24:52 CEST 2005


Angela Belda wrote:
> created some JNI modules to acces the xvid encoder/decoder from Java 
> code. Using Java Media Framework I can encode and decode live content 
> using native xvid and transmit it over RTP.

Nice! IMHO much better that using Java on all of the code. Scenarii may 
change, but signal processing is I believe something that should be left 
to lower level languages.

> in a xvid encoded stream, because the decoder already supports this 
> option and it didn't seem very difficult. I create the markers with the 

Yes it does, although, maybe in a minimalistic way. And I still don't 
understand what this is supposed to follow in the standard in decoder.c:

----8<-----
                 /* skip stuffing */
                 while (BitstreamShowBits(bs, 9) == 1)
                     BitstreamSkip(bs, 9);
---->8-----
I 've commented it out, and had no problem with decoding streams, but I 
have checked that many streams to draw any valid conclusion.

> following method:
> 
> void write_video_packet_header(Bitstream * const bs,
>                        const MBParam * pParam,
>                        const FRAMEINFO * const frame,
>                        int mbnum){
[SNIP]

Compared to (this code is to be licensed under the one used by XviD):
----8<-----
/* Minor optimization from ffmpeg project - LGPL license */
static uint32_t __inline
log2bin(uint32_t value)
{
     static const uint8_t log2_tab[256]={
         0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
         5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
         6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
         6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
         7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
     };
	int n = 0;

     if (value & 0xffff0000) {
         value >>= 16;
         n += 16;
     }
     if (value & 0xff00) {
         value >>= 8;
         n += 8;
     }
     while (value) {
         value >>= 1;
         n++;
     }
     return n+log2_tab[value];
}

int32_t
write_video_packet_header(Bitstream * const bs,
                           Bitstream * const bs2,
                           Bitstream * const bs_tex,
                           const FRAMEINFO * const frame,
                           const MBParam * pParam,
                           MACROBLOCK *pMB,
                           int32_t macroblock_number)
{
     int rm_size; /* resynch marker length */
     int mb_size = log2bin(pParam->mb_width*pParam->mb_height - 1);

     /* Shape is always rectangular */

     /* Set total resynch marker length ('0's followed by '1') */
     switch(frame->coding_type) {
     case I_VOP: rm_size = NUMBITS_VP_RESYNC_MARKER; break;
     case P_VOP:
     case S_VOP: rm_size = NUMBITS_VP_RESYNC_MARKER+frame->fcode-1; break;
     case B_VOP: rm_size = NUMBITS_VP_RESYNC_MARKER+MAX(1, 
frame->fcode); break;
     default:
         DPRINTF(XVID_DEBUG_ERROR, "VP with type=%i", frame->coding_type);
         rm_size = NUMBITS_VP_RESYNC_MARKER;
     }

     if (frame->vop_flags & XVID_VOP_DATA_PARTITIONED) {
         /* Make sure they are reset */
         BitstreamReset(bs2);
         BitstreamReset(bs_tex);
     }

     /* Write resynch marker */
     BitstreamPutBits(bs, 1, rm_size);

     /* Write macroblock number */
     BitstreamPutBits(bs, macroblock_number, mb_size);

     BitstreamPutBits(bs, pMB->quant, 5); /* quant_scale */
     if (pMB->mode == MODE_INTER_Q || pMB->mode == MODE_INTRA_Q) {
         pMB->dquant = 0;
         pMB->mode--;
     }
     BitstreamPutBits(bs, 0, 1); /* No HEC */

     return rm_size + mb_size + 5 + 1;
}
---->8----
It might be still unsufficient, and I haven't checked the dquant stuff.

> Then I modify the methods FrameCodeI and FrameCodeP to reset MV 
> prediction on boundaries. With I Frames I introduce a resync marker when 

And AC/DC prediction, too. I pass in the slice first macroblock index 
for this. The AC/DC prediction functions already support this, so it was 
a rather simple. For FrameCodeP, this amounts to this:

----8<----
/* Recompute pmvs for MBs when predictors available have changed */
if ((pEnc->current->vop_flags & XVID_VOP_HAS_SLICES) &&
     index-slice_start < mb_width) {
     if (pParam->vol_flags & XVID_VOL_QUARTERPEL) {
         for (k=0; k<(pMB->mode == MODE_INTER4V ? 4 : 1); k++) {
             VECTOR predMV =
                 get_qpmv2(current->mbs, mb_width, slice_start, x, y, k);
             /* XXX pmvs or qmvs ? */
             pMB->pmvs[k].x = pMB->mvs[k].x - predMV.x;
             pMB->pmvs[k].y = pMB->mvs[k].y - predMV.y;
         }
     } else {
         for (k=0; k<(pMB->mode == MODE_INTER4V ? 4 : 1); k++) {
              VECTOR predMV =
                 get_pmv2(current->mbs, mb_width, slice_start, x, y, k);
              pMB->pmvs[k].x = pMB->mvs[k].x - predMV.x;
              pMB->pmvs[k].y = pMB->mvs[k].y - predMV.y;
         }
     }
}

MBCoding(current, pMB, qcoeff, bs, bs2, bs_tex, &pEnc->current->sStat);
stop_coding_timer();
----8<----

> the number of bits encoded reaches a specified value, as specified in 
> the standard, but that seems not to possible with P frames, because I 
> need to know where to reset the MV prediction before encoding. I have 

I managed to. I'm just waiting for my patch to be applied in anyway so 
as to synchronize my code with the XviD CVS.

> modified the method MotionEstimation to reset MV prediction  
> periodically, each fixed number of macroblocks and it seems to work 

I also wanted to modify the motion estimation, but it is rather useless, 
as that's mostly the RDO decisions that may not take into account the 
slice prediction resets. That's mostly coding hints.

> fine, but I am not sure what to do to introduce  the resync markers  as 
> specified in the standard. Any ideas?

I did it that way (very crude) at the top of the loop where the previous 
code snippet is (GPL license still):
----8<----
if (pEnc->current->vop_flags & XVID_VOP_HAS_SLICES) {
      if (bitcount > pEnc->slice_bits)
           DPRINTF(XVID_DEBUG_ERROR, "VP overflow: %li/%li\n",
                   bitcount, pEnc->slice_bits);

      /* Approximative way not to overflow the requested
       * bitcount per slices */
      if (bitcount + mbcount + (mbcount>>1) + 8 > pEnc->slice_bits) {
           DPRINTF(XVID_DEBUG_MB, "VP size: %li/%li (MB %li was %li)\n",
                   bitcount, pEnc->slice_bits, index-1, mbcount);
           write_video_packet_end(bs, bs2, bs_tex, pEnc->current);
           /* TODO: put a callback here
            * Plugin-like stuff would be sweet */
           slice_start = index;
           bitcount =
               write_video_packet_header(bs, bs2, bs_tex, &pEnc->current,
                                         &pEnc->mbParam, pMB,
                                         slice_start);
      }
      else bitcount += mbcount;
}
---->8----
There are more places where to check the bitstream sizes.

> encoded frames before encapsulating over RTP. I had the idea to create a 
> new output parameter in the encoder. This new parameter would be an 
> array of bitstream positions where resync markers were introduced. The 

I'm not sure about this atm, but are resync markers byte-aligned (as 
opposed to VP start codes)? I plan too to modify the API, but it would 
be more like:
start_sliced_frame();
while (MB_left) {
     encode_slice();
     if (RTP) {
         do_RTP_magic();
         reset_whatever_needs_resetting_in_xvid();
     }
}
end_sliced_frame();

I haven't written a single line for this, there's too many things 
awaiting me in the next code synch. As I've stated in my very first mail 
to this list, wherever parameters for level at profile are set, there 
should also be something to enforce a packet maximal size - and this 
would be the first step.

> other possibility would be to look for these resync markers direct in 
> Java, before packetizing, but if I cannot know a fixed minimum number of 
> bytes between resync markers I should look in the whole bitstrem, 

Yes, that's why encode_slice() above should eventually return the size 
reached.

> shouldn't I?. Any suggestions?

While it would be straying away from the codec-only aspect of XviD, I 
believe XviD is the best place for this. This in spite of the difficulty 
to provided an usable API for callers that wish to have something RTP 
packetization on top of XviD.

Good luck with your implementation.

Regards,
sigdrak


More information about the XviD-devel mailing list