mpeg SVCD compatibility, SCR fixes, standard compliance
- fixed VBR+constrained bitstream header flags for non-VCD - more sane (and SVCD compatible) value for video stream->max_buffer_size - always write at least one PES header stuffing byte for MPEG-2 to prevent accidental start code generation - do not write more than 16 stuffing bytes in a PES header (not allowed). Use padding packets instead. - include a PES extension in the first MPEG-2 packet - fill the first pack of SVCD files with padding - "sanity hack" that prevents the SCR from overtaking the PTS for non-VCD - fixed VCD PTS values to correspond to the SCR - always include DTS in the first SVCD packet (fixes lots of compatibility problems with DVD players) patch by (Hauke Duden <H.NS.Duden at gmx dot net>) Originally committed as revision 3078 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
		
							parent
							
								
									ae4b7d5947
								
							
						
					
					
						commit
						224944895e
					
				@ -144,11 +144,14 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str
 | 
			
		||||
    } else
 | 
			
		||||
        put_bits(&pb, 6, s->audio_bound);
 | 
			
		||||
 | 
			
		||||
    if (s->is_vcd)
 | 
			
		||||
        put_bits(&pb, 1, 0); /* see VCD standard, p. IV-7*/
 | 
			
		||||
    else
 | 
			
		||||
        put_bits(&pb, 1, 1); /* variable bitrate*/
 | 
			
		||||
    put_bits(&pb, 1, 1); /* non constrainted bit stream */
 | 
			
		||||
    if (s->is_vcd) {
 | 
			
		||||
        /* see VCD standard, p. IV-7*/
 | 
			
		||||
        put_bits(&pb, 1, 0); 
 | 
			
		||||
        put_bits(&pb, 1, 1);
 | 
			
		||||
    } else {
 | 
			
		||||
        put_bits(&pb, 1, 0); /* variable bitrate*/
 | 
			
		||||
        put_bits(&pb, 1, 0); /* non constrainted bit stream */
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (s->is_vcd) {
 | 
			
		||||
        /* see VCD standard p IV-7 */
 | 
			
		||||
@ -286,6 +289,9 @@ static int mpeg_mux_init(AVFormatContext *ctx)
 | 
			
		||||
            } else {
 | 
			
		||||
                stream->id = mpa_id++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* This value HAS to be used for VCD (see VCD standard, p. IV-7).
 | 
			
		||||
               Right now it is also used for everything else.*/
 | 
			
		||||
            stream->max_buffer_size = 4 * 1024; 
 | 
			
		||||
            s->audio_bound++;
 | 
			
		||||
            break;
 | 
			
		||||
@ -294,7 +300,13 @@ static int mpeg_mux_init(AVFormatContext *ctx)
 | 
			
		||||
            if (s->scr_stream_index == -1)
 | 
			
		||||
                s->scr_stream_index = i;
 | 
			
		||||
            stream->id = mpv_id++;
 | 
			
		||||
            stream->max_buffer_size = 46 * 1024; 
 | 
			
		||||
            if (s->is_vcd)
 | 
			
		||||
                /* see VCD standard, p. IV-7*/
 | 
			
		||||
                stream->max_buffer_size = 46 * 1024; 
 | 
			
		||||
            else
 | 
			
		||||
                /* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2).
 | 
			
		||||
                   Right now it is also used for everything else.*/
 | 
			
		||||
                stream->max_buffer_size = 230 * 1024; 
 | 
			
		||||
            s->video_bound++;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
@ -465,7 +477,8 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->is_vcd && stream->packet_number==0)
 | 
			
		||||
    if ((s->is_vcd && stream->packet_number==0)
 | 
			
		||||
        || (s->is_svcd && s->packet_number==0))
 | 
			
		||||
        /* the first pack of each stream contains only the pack header,
 | 
			
		||||
           the system header and some padding (see VCD standard p. IV-6) 
 | 
			
		||||
           Add the padding size, so that the actual payload becomes 0.*/
 | 
			
		||||
@ -473,8 +486,12 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
    else {
 | 
			
		||||
        /* packet header size */
 | 
			
		||||
        buf_index += 6;
 | 
			
		||||
        if (s->is_mpeg2)
 | 
			
		||||
        if (s->is_mpeg2) {
 | 
			
		||||
            buf_index += 3;
 | 
			
		||||
            if (stream->packet_number==0)
 | 
			
		||||
                buf_index += 3; /* PES extension */
 | 
			
		||||
            buf_index += 1;    /* obligatory stuffing byte */
 | 
			
		||||
        }
 | 
			
		||||
        if (pts != AV_NOPTS_VALUE) {
 | 
			
		||||
            if (dts != pts)
 | 
			
		||||
                buf_index += 5 + 5;
 | 
			
		||||
@ -554,6 +571,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
    uint8_t buffer[128];
 | 
			
		||||
    int zero_trail_bytes = 0;
 | 
			
		||||
    int pad_packet_bytes = 0;
 | 
			
		||||
    int pes_flags;
 | 
			
		||||
    int general_pack = 0;  /*"general" pack without data specific to one stream?*/
 | 
			
		||||
    
 | 
			
		||||
    id = stream->id;
 | 
			
		||||
    
 | 
			
		||||
@ -595,11 +614,16 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
           each audio pack (see standard p. IV-8).*/
 | 
			
		||||
        zero_trail_bytes += 20;
 | 
			
		||||
            
 | 
			
		||||
    if (s->is_vcd && stream->packet_number==0) {
 | 
			
		||||
        /* the first pack of each stream contains only the pack header,
 | 
			
		||||
    if ((s->is_vcd && stream->packet_number==0)
 | 
			
		||||
        || (s->is_svcd && s->packet_number==0)) {
 | 
			
		||||
        /* for VCD the first pack of each stream contains only the pack header,
 | 
			
		||||
           the system header and lots of padding (see VCD standard p. IV-6).
 | 
			
		||||
           In the case of an audio pack, 20 zero bytes are also added at
 | 
			
		||||
           the end.*/
 | 
			
		||||
        /* For SVCD we fill the very first pack to increase compatibility with
 | 
			
		||||
           some DVD players. Not mandated by the standard.*/
 | 
			
		||||
        if (s->is_svcd)
 | 
			
		||||
            general_pack = 1;    /* the system header refers to both streams and no stream data*/
 | 
			
		||||
        pad_packet_bytes = packet_size - zero_trail_bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -613,6 +637,9 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
        /* packet header */
 | 
			
		||||
        if (s->is_mpeg2) {
 | 
			
		||||
            header_len = 3;
 | 
			
		||||
            if (stream->packet_number==0)
 | 
			
		||||
                header_len += 3; /* PES extension */
 | 
			
		||||
            header_len += 1; /* obligatory stuffing byte */
 | 
			
		||||
        } else {
 | 
			
		||||
            header_len = 0;
 | 
			
		||||
        }
 | 
			
		||||
@ -639,6 +666,13 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
        stuffing_size = payload_size - stream->buffer_ptr;
 | 
			
		||||
        if (stuffing_size < 0)
 | 
			
		||||
            stuffing_size = 0;
 | 
			
		||||
        if (stuffing_size > 16) {    /*<=16 for MPEG-1, <=32 for MPEG-2*/
 | 
			
		||||
            pad_packet_bytes += stuffing_size;
 | 
			
		||||
            packet_size -= stuffing_size;
 | 
			
		||||
            payload_size -= stuffing_size;
 | 
			
		||||
            stuffing_size = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        put_be32(&ctx->pb, startcode);
 | 
			
		||||
 | 
			
		||||
        put_be16(&ctx->pb, packet_size);
 | 
			
		||||
@ -650,21 +684,39 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
        if (s->is_mpeg2) {
 | 
			
		||||
            put_byte(&ctx->pb, 0x80); /* mpeg2 id */
 | 
			
		||||
 | 
			
		||||
            pes_flags=0;
 | 
			
		||||
 | 
			
		||||
            if (pts != AV_NOPTS_VALUE) {
 | 
			
		||||
                if (dts != pts) {
 | 
			
		||||
                    put_byte(&ctx->pb, 0xc0); /* flags */
 | 
			
		||||
                    put_byte(&ctx->pb, header_len - 3 + stuffing_size);
 | 
			
		||||
                    put_timestamp(&ctx->pb, 0x03, pts);
 | 
			
		||||
                    put_timestamp(&ctx->pb, 0x01, dts);
 | 
			
		||||
                } else {
 | 
			
		||||
                    put_byte(&ctx->pb, 0x80); /* flags */
 | 
			
		||||
                    put_byte(&ctx->pb, header_len - 3 + stuffing_size);
 | 
			
		||||
                    put_timestamp(&ctx->pb, 0x02, pts);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                put_byte(&ctx->pb, 0x00); /* flags */
 | 
			
		||||
                put_byte(&ctx->pb, header_len - 3 + stuffing_size);
 | 
			
		||||
                pes_flags |= 0x80;
 | 
			
		||||
                if (dts != pts)
 | 
			
		||||
                    pes_flags |= 0x40;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Both the MPEG-2 and the SVCD standards demand that the
 | 
			
		||||
               P-STD_buffer_size field be included in the first packet of
 | 
			
		||||
               every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2
 | 
			
		||||
               and MPEG-2 standard 2.7.7) */
 | 
			
		||||
            if (stream->packet_number == 0)
 | 
			
		||||
                pes_flags |= 0x01;
 | 
			
		||||
 | 
			
		||||
            put_byte(&ctx->pb, pes_flags); /* flags */
 | 
			
		||||
            put_byte(&ctx->pb, header_len - 3 + stuffing_size);
 | 
			
		||||
 | 
			
		||||
            if (pes_flags & 0x80)  /*write pts*/
 | 
			
		||||
                put_timestamp(&ctx->pb, (pes_flags & 0x40) ? 0x03 : 0x02, pts);
 | 
			
		||||
            if (pes_flags & 0x40)  /*write dts*/
 | 
			
		||||
                put_timestamp(&ctx->pb, 0x01, dts);
 | 
			
		||||
            
 | 
			
		||||
            if (pes_flags & 0x01) {  /*write pes extension*/
 | 
			
		||||
                put_byte(&ctx->pb, 0x10); /* flags */
 | 
			
		||||
 | 
			
		||||
                /* P-STD buffer info */                
 | 
			
		||||
                if (id == AUDIO_ID)
 | 
			
		||||
                    put_be16(&ctx->pb, 0x4000 | stream->max_buffer_size/128);
 | 
			
		||||
                else
 | 
			
		||||
                    put_be16(&ctx->pb, 0x6000 | stream->max_buffer_size/1024);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            if (pts != AV_NOPTS_VALUE) {
 | 
			
		||||
                if (dts != pts) {
 | 
			
		||||
@ -694,9 +746,14 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (s->is_mpeg2)
 | 
			
		||||
        if (s->is_mpeg2) {
 | 
			
		||||
            /* special stuffing byte that is always written
 | 
			
		||||
               to prevent accidental generation of start codes. */
 | 
			
		||||
            put_byte(&ctx->pb, 0xff);
 | 
			
		||||
 | 
			
		||||
            for(i=0;i<stuffing_size;i++)
 | 
			
		||||
                put_byte(&ctx->pb, 0xff);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* output data */
 | 
			
		||||
        put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size);
 | 
			
		||||
@ -711,7 +768,12 @@ static void flush_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
    put_flush_packet(&ctx->pb);
 | 
			
		||||
    
 | 
			
		||||
    s->packet_number++;
 | 
			
		||||
    stream->packet_number++;
 | 
			
		||||
 | 
			
		||||
    /* only increase the stream packet number if this pack actually contains
 | 
			
		||||
       something that is specific to this stream! I.e. a dedicated header
 | 
			
		||||
       or some data.*/
 | 
			
		||||
    if (!general_pack)
 | 
			
		||||
        stream->packet_number++;
 | 
			
		||||
    stream->nb_frames = 0;
 | 
			
		||||
    stream->frame_start_offset = 0;
 | 
			
		||||
}
 | 
			
		||||
@ -781,6 +843,7 @@ static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts,
 | 
			
		||||
        pts = timestamp;
 | 
			
		||||
        dts = timestamp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *ppts = pts & ((1LL << 33) - 1);
 | 
			
		||||
    *pdts = dts & ((1LL << 33) - 1);
 | 
			
		||||
}
 | 
			
		||||
@ -789,8 +852,10 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts)
 | 
			
		||||
{
 | 
			
		||||
    MpegMuxContext *s = ctx->priv_data;
 | 
			
		||||
    int64_t scr;
 | 
			
		||||
    StreamInfo *stream;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (s->is_vcd)
 | 
			
		||||
    if (s->is_vcd) {
 | 
			
		||||
        /* Since the data delivery rate is constant, SCR is computed
 | 
			
		||||
           using the formula C + i * 1200 where C is the start constant
 | 
			
		||||
           and i is the pack index.
 | 
			
		||||
@ -802,7 +867,21 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts)
 | 
			
		||||
           will still be correct according to the standard. It just won't have
 | 
			
		||||
           the "recommended" value).*/
 | 
			
		||||
        scr = 36000 + s->packet_number * 1200;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
        for(i=0;i<ctx->nb_streams;i++) {
 | 
			
		||||
            stream = ctx->streams[i]->priv_data;
 | 
			
		||||
            
 | 
			
		||||
            if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) {
 | 
			
		||||
                av_log(ctx, AV_LOG_DEBUG, "mpeg vcd: SCR above PTS (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0);                 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        /* XXX I believe this calculation of SCR is wrong. SCR
 | 
			
		||||
           specifies at which time the data should enter the decoder.
 | 
			
		||||
           Two packs cannot enter the decoder at the same time. */
 | 
			
		||||
@ -814,6 +893,17 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts)
 | 
			
		||||
            scr = pts;
 | 
			
		||||
        else
 | 
			
		||||
            scr = s->last_scr;
 | 
			
		||||
 | 
			
		||||
        /* "Sanity hack": make sure that the SCR does not overtake the pts of
 | 
			
		||||
           buffered data that is still waiting to be written.*/
 | 
			
		||||
        for(i=0;i<ctx->nb_streams;i++) {
 | 
			
		||||
            stream = ctx->streams[i]->priv_data;
 | 
			
		||||
            
 | 
			
		||||
            if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) {
 | 
			
		||||
                /* av_log(ctx, AV_LOG_DEBUG, "mpeg: restricting scr to stream pts (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); */
 | 
			
		||||
                scr = stream->start_pts;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->last_scr=scr;
 | 
			
		||||
@ -834,6 +924,28 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,
 | 
			
		||||
    
 | 
			
		||||
    compute_pts_dts(st, &pts, &dts, timestamp);
 | 
			
		||||
 | 
			
		||||
    if(s->is_svcd) {
 | 
			
		||||
        /* offset pts and dts slightly into the future to be able
 | 
			
		||||
           to do the compatibility fix below.*/
 | 
			
		||||
        pts = (pts + 2) & ((1LL << 33) - 1);
 | 
			
		||||
        dts = (dts + 2) & ((1LL << 33) - 1);
 | 
			
		||||
 | 
			
		||||
        if (stream->packet_number == 0 && dts == pts)
 | 
			
		||||
            /* For the very first packet we want to force the DTS to be included.
 | 
			
		||||
               This increases compatibility with lots of DVD players.
 | 
			
		||||
               Since the MPEG-2 standard mandates that DTS is only written when
 | 
			
		||||
               it is different from PTS we have to move it slightly into the past.*/
 | 
			
		||||
            dts = (dts - 2) & ((1LL << 33) - 1);
 | 
			
		||||
    }
 | 
			
		||||
    if(s->is_vcd) {
 | 
			
		||||
        /* We have to offset the PTS, so that it is consistent with the SCR.
 | 
			
		||||
           SCR starts at 36000, but the first two packs contain only padding
 | 
			
		||||
           and the first pack from the other stream, respectively, may also have
 | 
			
		||||
           been written before.
 | 
			
		||||
           So the real data starts at SCR 36000+3*1200. */
 | 
			
		||||
        pts = (pts + 36000 + 3600) & ((1LL << 33) - 1);
 | 
			
		||||
        dts = (dts + 36000 + 3600) & ((1LL << 33) - 1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
#if 0
 | 
			
		||||
    update_scr(ctx,stream_index,pts);
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ b166e89a9ec8c707573329d883c1b6f9 *./data/b-libav.asf
 | 
			
		||||
./data/b-libav.asf CRC=525fdb22
 | 
			
		||||
be8eb1b5705c8105e4727258e448cb24 *./data/b-libav.rm
 | 
			
		||||
 356950 ./data/b-libav.rm
 | 
			
		||||
072645ee8b36e432227cf9dff21561f0 *./data/b-libav.mpg
 | 
			
		||||
e826aa1637ff15144ab484c1efca7fe7 *./data/b-libav.mpg
 | 
			
		||||
 382976 ./data/b-libav.mpg
 | 
			
		||||
./data/b-libav.mpg CRC=eda0e29e
 | 
			
		||||
01a4130e776b8955fa99e477113e94fd *./data/b-libav.swf
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user