[xiph-commits] r16966 - experimental/derf/theora-ptalarbvorm/lib
tterribe at svn.xiph.org
tterribe at svn.xiph.org
Sat Mar 13 12:57:39 PST 2010
Author: tterribe
Date: 2010-03-13 12:57:39 -0800 (Sat, 13 Mar 2010)
New Revision: 16966
Modified:
experimental/derf/theora-ptalarbvorm/lib/decode.c
experimental/derf/theora-ptalarbvorm/lib/encode.c
Log:
Update how dropped/duplicate frames are handled in VP3 compatibility mode.
We now write an old-style "inter frame with no coded blocks" in this mode
instead of the more-efficient 0-byte packet.
The rationale is detailed in the comments for oc_enc_drop_frame_pack() in
encode.c.
To allow applications to handle the old-style drop frames efficiently, the
decoder has been updated to return TH_DUPFRAME on _any_ frame with no coded
blocks, not just on 0-byte packets.
Thus, the application can skip color conversion and avoid updating the display
on these frames.
Modified: experimental/derf/theora-ptalarbvorm/lib/decode.c
===================================================================
--- experimental/derf/theora-ptalarbvorm/lib/decode.c 2010-03-13 00:37:24 UTC (rev 16965)
+++ experimental/derf/theora-ptalarbvorm/lib/decode.c 2010-03-13 20:57:39 UTC (rev 16966)
@@ -2056,7 +2056,9 @@
int cheight;
_dec->state.ref_frame_idx[OC_FRAME_GOLD]=0;
_dec->state.ref_frame_idx[OC_FRAME_PREV]=0;
- _dec->state.ref_frame_idx[OC_FRAME_SELF]=1;
+ _dec->state.ref_frame_idx[OC_FRAME_SELF]=0;
+ memcpy(_dec->pp_frame_buf,_dec->state.ref_frame_bufs[0],
+ sizeof(_dec->pp_frame_buf[0])*3);
info=&_dec->state.info;
yhstride=info->frame_width+2*OC_UMV_PADDING;
yheight=info->frame_height+2*OC_UMV_PADDING;
@@ -2072,9 +2074,35 @@
int ret;
if(_dec==NULL||_op==NULL)return TH_EFAULT;
/*A completely empty packet indicates a dropped frame and is treated exactly
- like an inter frame with no coded blocks.
- Only proceed if we have a non-empty packet.*/
- if(_op->bytes!=0){
+ like an inter frame with no coded blocks.*/
+ if(_op->bytes==0){
+ _dec->state.frame_type=OC_INTER_FRAME;
+ _dec->state.ntotal_coded_fragis=0;
+ }
+ else{
+ oc_pack_readinit(&_dec->opb,_op->packet,_op->bytes);
+ ret=oc_dec_frame_header_unpack(_dec);
+ if(ret<0)return ret;
+ if(_dec->state.frame_type==OC_INTRA_FRAME)oc_dec_mark_all_intra(_dec);
+ else oc_dec_coded_flags_unpack(_dec);
+ }
+ /*If there have been no reference frames, and we need one, initialize one.*/
+ if(_dec->state.frame_type!=OC_INTRA_FRAME&&
+ (_dec->state.ref_frame_idx[OC_FRAME_GOLD]<0||
+ _dec->state.ref_frame_idx[OC_FRAME_PREV]<0)){
+ oc_dec_init_dummy_frame(_dec);
+ }
+ /*If this was an inter frame with no coded blocks...*/
+ if(_dec->state.ntotal_coded_fragis<=0){
+ /*Just update the granule position and return.*/
+ _dec->state.granpos=(_dec->state.keyframe_num+_dec->state.granpos_bias<<
+ _dec->state.info.keyframe_granule_shift)
+ +(_dec->state.curframe_num-_dec->state.keyframe_num);
+ _dec->state.curframe_num++;
+ if(_granpos!=NULL)*_granpos=_dec->state.granpos;
+ return TH_DUPFRAME;
+ }
+ else{
oc_dec_pipeline_state pipe;
th_ycbcr_buffer stripe_buf;
int stripe_fragy;
@@ -2082,28 +2110,14 @@
int pli;
int notstart;
int notdone;
- oc_pack_readinit(&_dec->opb,_op->packet,_op->bytes);
+ /*Select a free buffer to use for the reconstructed version of this frame.*/
+ for(refi=0;refi==_dec->state.ref_frame_idx[OC_FRAME_GOLD]||
+ refi==_dec->state.ref_frame_idx[OC_FRAME_PREV];refi++);
+ _dec->state.ref_frame_idx[OC_FRAME_SELF]=refi;
#if defined(HAVE_CAIRO)
_dec->telemetry_frame_bytes=_op->bytes;
#endif
- ret=oc_dec_frame_header_unpack(_dec);
- if(ret<0)return ret;
- /*Select a free buffer to use for the reconstructed version of this
- frame.*/
- if(_dec->state.frame_type!=OC_INTRA_FRAME&&
- (_dec->state.ref_frame_idx[OC_FRAME_GOLD]<0||
- _dec->state.ref_frame_idx[OC_FRAME_PREV]<0)){
- /*No reference frames yet!*/
- oc_dec_init_dummy_frame(_dec);
- refi=_dec->state.ref_frame_idx[OC_FRAME_SELF];
- }
- else{
- for(refi=0;refi==_dec->state.ref_frame_idx[OC_FRAME_GOLD]||
- refi==_dec->state.ref_frame_idx[OC_FRAME_PREV];refi++);
- _dec->state.ref_frame_idx[OC_FRAME_SELF]=refi;
- }
if(_dec->state.frame_type==OC_INTRA_FRAME){
- oc_dec_mark_all_intra(_dec);
_dec->state.keyframe_num=_dec->state.curframe_num;
#if defined(HAVE_CAIRO)
_dec->telemetry_coding_bytes=
@@ -2112,7 +2126,6 @@
#endif
}
else{
- oc_dec_coded_flags_unpack(_dec);
#if defined(HAVE_CAIRO)
_dec->telemetry_coding_bytes=oc_pack_bytes_left(&_dec->opb);
#endif
@@ -2262,30 +2275,11 @@
gamma values, if nothing else).*/
oc_restore_fpu(&_dec->state);
#if defined(OC_DUMP_IMAGES)
- /*Don't dump images for dropped frames.*/
+ /*We only dump images if there were some coded blocks.*/
oc_state_dump_frame(&_dec->state,OC_FRAME_SELF,"dec");
#endif
return 0;
}
- else{
- if(_dec->state.ref_frame_idx[OC_FRAME_GOLD]<0||
- _dec->state.ref_frame_idx[OC_FRAME_PREV]<0){
- int refi;
- /*No reference frames yet!*/
- oc_dec_init_dummy_frame(_dec);
- refi=_dec->state.ref_frame_idx[OC_FRAME_PREV];
- _dec->state.ref_frame_idx[OC_FRAME_SELF]=refi;
- memcpy(_dec->pp_frame_buf,_dec->state.ref_frame_bufs[refi],
- sizeof(_dec->pp_frame_buf[0])*3);
- }
- /*Just update the granule position and return.*/
- _dec->state.granpos=(_dec->state.keyframe_num+_dec->state.granpos_bias<<
- _dec->state.info.keyframe_granule_shift)
- +(_dec->state.curframe_num-_dec->state.keyframe_num);
- _dec->state.curframe_num++;
- if(_granpos!=NULL)*_granpos=_dec->state.granpos;
- return TH_DUPFRAME;
- }
}
int th_decode_ycbcr_out(th_dec_ctx *_dec,th_ycbcr_buffer _ycbcr){
Modified: experimental/derf/theora-ptalarbvorm/lib/encode.c
===================================================================
--- experimental/derf/theora-ptalarbvorm/lib/encode.c 2010-03-13 00:37:24 UTC (rev 16965)
+++ experimental/derf/theora-ptalarbvorm/lib/encode.c 2010-03-13 20:57:39 UTC (rev 16966)
@@ -887,7 +887,50 @@
#endif
}
+/*Packs an explicit drop frame, instead of using the more efficient 0-byte
+ packet.
+ This is only enabled in VP3-compatibility mode, even though it is not
+ strictly required for VP3 compatibility (VP3 could be encoded in AVI, which
+ also supports dropping frames by inserting 0 byte packets).
+ However, almost every _Theora_ player used to get this wrong (and many still
+ do), and it wasn't until we started shipping a post-VP3 encoder that
+ actually non-VP3 features that this began to be discovered and fixed,
+ despite being in the standard since 2004.*/
+static void oc_enc_drop_frame_pack(oc_enc_ctx *_enc){
+ unsigned nsbs;
+ oggpackB_reset(&_enc->opb);
+ /*Mark this as a data packet.*/
+ oggpackB_write(&_enc->opb,0,1);
+ /*Output the frame type (key frame or delta frame).*/
+ oggpackB_write(&_enc->opb,OC_INTER_FRAME,1);
+ /*Write out the current qi list.
+ We always use just 1 qi, to avoid wasting bits on the others.*/
+ oggpackB_write(&_enc->opb,_enc->state.qis[0],6);
+ oggpackB_write(&_enc->opb,0,1);
+ /*Coded block flags: everything is uncoded.*/
+ nsbs=_enc->state.nsbs;
+ /*No partially coded SBs.*/
+ oggpackB_write(&_enc->opb,0,1);
+ oc_sb_run_pack(&_enc->opb,nsbs,0,1);
+ /*No fully coded SBs.*/
+ oggpackB_write(&_enc->opb,0,1);
+ oc_sb_run_pack(&_enc->opb,nsbs,0,1);
+ /*MB modes: just need write which scheme to use.
+ Since we have no coded MBs, we can pick any of them except 0, which would
+ require writing out an additional mode list.*/
+ oggpackB_write(&_enc->opb,7,3);
+ /*MVs: just need write which scheme to use.
+ We can pick either one, since we have no MVs.*/
+ oggpackB_write(&_enc->opb,1,1);
+ /*Write the chosen DC token tables.*/
+ oggpackB_write(&_enc->opb,_enc->huff_idxs[OC_INTER_FRAME][0][0],4);
+ oggpackB_write(&_enc->opb,_enc->huff_idxs[OC_INTER_FRAME][0][1],4);
+ /*Write the chosen AC token tables.*/
+ oggpackB_write(&_enc->opb,_enc->huff_idxs[OC_INTER_FRAME][1][0],4);
+ oggpackB_write(&_enc->opb,_enc->huff_idxs[OC_INTER_FRAME][1][1],4);
+}
+
void oc_enc_vtable_init_c(oc_enc_ctx *_enc){
/*The implementations prefixed with oc_enc_ are encoder-specific.
The rest we re-use from the decoder.*/
@@ -1157,8 +1200,10 @@
_enc->state.ref_frame_idx[OC_FRAME_PREV];
/*Flag motion vector analysis about the frame drop.*/
_enc->prevframe_dropped=1;
- /*Zero the packet.*/
- oggpackB_reset(&_enc->opb);
+ /*Emit an inter frame with no coded blocks in VP3-compatibility mode.*/
+ if(_enc->vp3_compatible)oc_enc_drop_frame_pack(_enc);
+ /*Otherwise zero the packet.*/
+ else oggpackB_reset(&_enc->opb);
}
static void oc_enc_compress_keyframe(oc_enc_ctx *_enc,int _recode){
@@ -1606,11 +1651,11 @@
}
int th_encode_packetout(th_enc_ctx *_enc,int _last_p,ogg_packet *_op){
+ unsigned char *packet;
if(_enc==NULL||_op==NULL)return TH_EFAULT;
if(_enc->packet_state==OC_PACKET_READY){
_enc->packet_state=OC_PACKET_EMPTY;
if(_enc->rc.twopass!=1){
- unsigned char *packet;
packet=oggpackB_get_buffer(&_enc->opb);
/*If there's no packet, malloc failed while writing; it's lost forever.*/
if(packet==NULL)return TH_EFAULT;
@@ -1626,8 +1671,21 @@
else if(_enc->packet_state==OC_PACKET_EMPTY){
if(_enc->nqueued_dups>0){
_enc->nqueued_dups--;
- _op->packet=NULL;
- _op->bytes=0;
+ /*Emit an inter frame with no coded blocks in VP3-compatibility mode.*/
+ if(_enc->vp3_compatible){
+ oc_enc_drop_frame_pack(_enc);
+ packet=oggpackB_get_buffer(&_enc->opb);
+ /*If there's no packet, malloc failed while writing; it's lost
+ forever.*/
+ if(packet==NULL)return TH_EFAULT;
+ _op->packet=packet;
+ _op->bytes=oggpackB_bytes(&_enc->opb);
+ }
+ /*Otherwise emit a 0-byte packet.*/
+ else{
+ _op->packet=NULL;
+ _op->bytes=0;
+ }
}
else{
if(_last_p)_enc->packet_state=OC_PACKET_DONE;
More information about the commits
mailing list