📄 mpeg.c
字号:
if (s->is_vcd) { double overhead_rate; /* The VCD standard mandates that the mux_rate field is 3528 (see standard p. IV-6). The value is actually "wrong", i.e. if you calculate it using the normal formula and the 75 sectors per second transfer rate you get a different value because the real pack size is 2324, not 2352. But the standard explicitly specifies that the mux_rate field in the header must have this value.*/// s->mux_rate=2352 * 75 / 50; /* = 3528*/ /* The VCD standard states that the muxed stream must be exactly 75 packs / second (the data rate of a single speed cdrom). Since the video bitrate (probably 1150000 bits/sec) will be below the theoretical maximum we have to add some padding packets to make up for the lower data rate. (cf. VCD standard p. IV-6 )*/ /* Add the header overhead to the data rate. 2279 data bytes per audio pack, 2294 data bytes per video pack*/ overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279); overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294); overhead_rate *= 8; /* Add padding so that the full bitrate is 2324*75 bytes/sec */ s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate); } if (s->is_vcd || s->is_mpeg2) /* every packet */ s->pack_header_freq = 1; else /* every 2 seconds */ s->pack_header_freq = 2 * bitrate / s->packet_size / 8; /* the above seems to make pack_header_freq zero sometimes */ if (s->pack_header_freq == 0) s->pack_header_freq = 1; if (s->is_mpeg2) /* every 200 packets. Need to look at the spec. */ s->system_header_freq = s->pack_header_freq * 40; else if (s->is_vcd) /* the standard mandates that there are only two system headers in the whole file: one in the first packet of each stream. (see standard p. IV-7 and IV-8) */ s->system_header_freq = 0x7fffffff; else s->system_header_freq = s->pack_header_freq * 5; for(i=0;i<ctx->nb_streams;i++) { stream = ctx->streams[i]->priv_data; stream->packet_number = 0; } s->system_header_size = get_system_header_size(ctx); s->last_scr = 0; return 0; fail: for(i=0;i<ctx->nb_streams;i++) { av_free(ctx->streams[i]->priv_data); } return -ENOMEM;}static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp){ put_byte(pb, (id << 4) | (((timestamp >> 30) & 0x07) << 1) | 1); put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1)); put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1));}/* return the number of padding bytes that should be inserted into the multiplexed stream.*/static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts){ MpegMuxContext *s = ctx->priv_data; int pad_bytes = 0; if (s->vcd_padding_bitrate > 0 && pts!=AV_NOPTS_VALUE) { int64_t full_pad_bytes; full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); //FIXME this is wrong pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written); if (pad_bytes<0) /* might happen if we have already padded to a later timestamp. This can occur if another stream has already advanced further.*/ pad_bytes=0; } return pad_bytes;}#if 0 /* unused, remove? *//* return the exact available payload size for the next packet for stream 'stream_index'. 'pts' and 'dts' are only used to know if timestamps are needed in the packet header. */static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, int64_t pts, int64_t dts){ MpegMuxContext *s = ctx->priv_data; int buf_index; StreamInfo *stream; stream = ctx->streams[stream_index]->priv_data; buf_index = 0; if (((s->packet_number % s->pack_header_freq) == 0)) { /* pack header size */ if (s->is_mpeg2) buf_index += 14; else buf_index += 12; if (s->is_vcd) { /* there is exactly one system header for each stream in a VCD MPEG, One in the very first video packet and one in the very first audio packet (see VCD standard p. IV-7 and IV-8).*/ if (stream->packet_number==0) /* The system headers refer only to the stream they occur in, so they have a constant size.*/ buf_index += 15; } else { if ((s->packet_number % s->system_header_freq) == 0) buf_index += s->system_header_size; } } 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.*/ buf_index += s->packet_size - buf_index; else { /* packet header size */ buf_index += 6; 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; else buf_index += 5; } else { if (!s->is_mpeg2) buf_index++; } if (stream->id < 0xc0) { /* AC3/LPCM private data header */ buf_index += 4; if (stream->id >= 0xa0) { int n; buf_index += 3; /* NOTE: we round the payload size to an integer number of LPCM samples */ n = (s->packet_size - buf_index) % stream->lpcm_align; if (n) buf_index += (stream->lpcm_align - n); } } if (s->is_vcd && stream->id == AUDIO_ID) /* The VCD standard demands that 20 zero bytes follow each audio packet (see standard p. IV-8).*/ buf_index+=20; } return s->packet_size - buf_index;}#endif/* Write an MPEG padding packet header. */static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes){ MpegMuxContext *s = ctx->priv_data; int i; put_be32(pb, PADDING_STREAM); put_be16(pb, packet_bytes - 6); if (!s->is_mpeg2) { put_byte(pb, 0x0f); packet_bytes -= 7; } else packet_bytes -= 6; for(i=0;i<packet_bytes;i++) put_byte(pb, 0xff);}static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){ int nb_frames=0; PacketDesc *pkt_desc= stream->premux_packet; while(len>0){ if(pkt_desc->size == pkt_desc->unwritten_size) nb_frames++; len -= pkt_desc->unwritten_size; pkt_desc= pkt_desc->next; } return nb_frames;}/* flush the packet on stream stream_index */static int flush_packet(AVFormatContext *ctx, int stream_index, int64_t pts, int64_t dts, int64_t scr, int trailer_size){ MpegMuxContext *s = ctx->priv_data; StreamInfo *stream = ctx->streams[stream_index]->priv_data; uint8_t *buf_ptr; int size, payload_size, startcode, id, stuffing_size, i, header_len; int packet_size; 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?*/ int nb_frames; id = stream->id;#if 0 printf("packet ID=%2x PTS=%0.3f\n", id, pts / 90000.0);#endif buf_ptr = buffer; if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) { /* output pack and systems header if needed */ size = put_pack_header(ctx, buf_ptr, scr); buf_ptr += size; s->last_scr= scr; if (s->is_vcd) { /* there is exactly one system header for each stream in a VCD MPEG, One in the very first video packet and one in the very first audio packet (see VCD standard p. IV-7 and IV-8).*/ if (stream->packet_number==0) { size = put_system_header(ctx, buf_ptr, id); buf_ptr += size; } } else if (s->is_dvd) { if (stream->align_iframe || s->packet_number == 0){ int bytes_to_iframe; int PES_bytes_to_fill; if (stream->fifo_iframe_ptr >= stream->fifo.rptr) { bytes_to_iframe = stream->fifo_iframe_ptr - stream->fifo.rptr; } else { bytes_to_iframe = (stream->fifo.end - stream->fifo.rptr) + (stream->fifo_iframe_ptr - stream->fifo.buffer); } PES_bytes_to_fill = s->packet_size - size - 10; if (pts != AV_NOPTS_VALUE) { if (dts != pts) PES_bytes_to_fill -= 5 + 5; else PES_bytes_to_fill -= 5; } if (bytes_to_iframe == 0 || s->packet_number == 0) { size = put_system_header(ctx, buf_ptr, 0); buf_ptr += size; size = buf_ptr - buffer; put_buffer(&ctx->pb, buffer, size); put_be32(&ctx->pb, PRIVATE_STREAM_2); put_be16(&ctx->pb, 0x03d4); // length put_byte(&ctx->pb, 0x00); // substream ID, 00=PCI for (i = 0; i < 979; i++) put_byte(&ctx->pb, 0x00); put_be32(&ctx->pb, PRIVATE_STREAM_2); put_be16(&ctx->pb, 0x03fa); // length put_byte(&ctx->pb, 0x01); // substream ID, 01=DSI for (i = 0; i < 1017; i++) put_byte(&ctx->pb, 0x00); memset(buffer, 0, 128); buf_ptr = buffer; s->packet_number++; stream->align_iframe = 0; scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet size = put_pack_header(ctx, buf_ptr, scr); s->last_scr= scr; buf_ptr += size; /* GOP Start */ } else if (bytes_to_iframe < PES_bytes_to_fill) { pad_packet_bytes = PES_bytes_to_fill - bytes_to_iframe; } } } else { if ((s->packet_number % s->system_header_freq) == 0) { size = put_system_header(ctx, buf_ptr, 0); buf_ptr += size; } } } size = buf_ptr - buffer; put_buffer(&ctx->pb, buffer, size); packet_size = s->packet_size - size; if (s->is_vcd && id == AUDIO_ID) /* The VCD standard demands that 20 zero bytes follow each audio pack (see standard p. IV-8).*/ zero_trail_bytes += 20; 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; } packet_size -= pad_packet_bytes + zero_trail_bytes; if (packet_size > 0) { /* packet header size */ packet_size -= 6; /* 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; } if (pts != AV_NOPTS_VALUE) { if (dts != pts) header_len += 5 + 5; else header_len += 5; } else { if (!s->is_mpeg2) header_len++; } payload_size = packet_size - header_len; if (id < 0xc0) { startcode = PRIVATE_STREAM_1; payload_size -= 1; if (id >= 0x40) { payload_size -= 3; if (id >= 0xa0) payload_size -= 3; } } else { startcode = 0x100 + id; } stuffing_size = payload_size - fifo_size(&stream->fifo, stream->fifo.rptr); // first byte doesnt fit -> reset pts/dts + stuffing if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){ int timestamp_len=0; if(dts != pts) timestamp_len += 5; if(pts != AV_NOPTS_VALUE) timestamp_len += s->is_mpeg2 ? 5 : 4; pts=dts= AV_NOPTS_VALUE; header_len -= timestamp_len; if (s->is_dvd && stream->align_iframe) { pad_packet_bytes += timestamp_len; packet_size -= timestamp_len; } else { payload_size += timestamp_len; } stuffing_size += timestamp_len; if(payload_size > trailer_size) stuffing_size += payload_size - trailer_size; } if (pad_packet_bytes > 0 && pad_packet_bytes <= 7) { // can't use padding, so use stuffing packet_size += pad_packet_bytes; payload_size += pad_packet_bytes; // undo the previous adjustment if (stuffing_size < 0) { stuffing_size = pad_packet_bytes; } else { stuffing_size += pad_packet_bytes; } pad_packet_bytes = 0; } 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; } nb_frames= get_nb_frames(ctx, stream, payload_size - stuffing_size); put_be32(&ctx->pb, startcode); put_be16(&ctx->pb, packet_size); if (!s->is_mpeg2) for(i=0;i<stuffing_size;i++) put_byte(&ctx->pb, 0xff); if (s->is_mpeg2) { put_byte(&ctx->pb, 0x80); /* mpeg2 id */ pes_flags=0; if (pts != AV_NOPTS_VALUE) { 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*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -