📄 mpeg.c
字号:
/* * MPEG1/2 mux/demux * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "avformat.h"#define MAX_PAYLOAD_SIZE 4096#define NB_STREAMS 2typedef struct { uint8_t buffer[MAX_PAYLOAD_SIZE]; int buffer_ptr; uint8_t id; int max_buffer_size; /* in bytes */ int packet_number; int64_t start_pts;} StreamInfo;typedef struct { int packet_size; /* required packet size */ int packet_data_max_size; /* maximum data size inside a packet */ int packet_number; int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */ int system_header_freq; int mux_rate; /* bitrate in units of 50 bytes/s */ /* stream info */ int audio_bound; int video_bound; int is_mpeg2; int is_vcd;} MpegMuxContext;#define PACK_START_CODE ((unsigned int)0x000001ba)#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb)#define SEQUENCE_END_CODE ((unsigned int)0x000001b7)#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00)#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100)#define ISO_11172_END_CODE ((unsigned int)0x000001b9) /* mpeg2 */#define PROGRAM_STREAM_MAP 0x1bc#define PRIVATE_STREAM_1 0x1bd#define PADDING_STREAM 0x1be#define PRIVATE_STREAM_2 0x1bf#define AUDIO_ID 0xc0#define VIDEO_ID 0xe0#ifdef CONFIG_ENCODERSextern AVOutputFormat mpeg1system_mux;extern AVOutputFormat mpeg1vcd_mux;extern AVOutputFormat mpeg2vob_mux;static int put_pack_header(AVFormatContext *ctx, uint8_t *buf, int64_t timestamp){ MpegMuxContext *s = ctx->priv_data; PutBitContext pb; init_put_bits(&pb, buf, 128); put_bits(&pb, 32, PACK_START_CODE); if (s->is_mpeg2) { put_bits(&pb, 2, 0x1); } else { put_bits(&pb, 4, 0x2); } put_bits(&pb, 3, (uint32_t)((timestamp >> 30) & 0x07)); put_bits(&pb, 1, 1); put_bits(&pb, 15, (uint32_t)((timestamp >> 15) & 0x7fff)); put_bits(&pb, 1, 1); put_bits(&pb, 15, (uint32_t)((timestamp) & 0x7fff)); put_bits(&pb, 1, 1); if (s->is_mpeg2) { /* clock extension */ put_bits(&pb, 9, 0); put_bits(&pb, 1, 1); } put_bits(&pb, 1, 1); put_bits(&pb, 22, s->mux_rate); put_bits(&pb, 1, 1); if (s->is_mpeg2) { put_bits(&pb, 5, 0x1f); /* reserved */ put_bits(&pb, 3, 0); /* stuffing length */ } flush_put_bits(&pb); return pbBufPtr(&pb) - pb.buf;}static int put_system_header(AVFormatContext *ctx, uint8_t *buf){ MpegMuxContext *s = ctx->priv_data; int size, rate_bound, i, private_stream_coded, id; PutBitContext pb; init_put_bits(&pb, buf, 128); put_bits(&pb, 32, SYSTEM_HEADER_START_CODE); put_bits(&pb, 16, 0); put_bits(&pb, 1, 1); rate_bound = s->mux_rate; /* maximum bit rate of the multiplexed stream */ put_bits(&pb, 22, rate_bound); put_bits(&pb, 1, 1); /* marker */ put_bits(&pb, 6, s->audio_bound); put_bits(&pb, 1, 1); /* variable bitrate */ put_bits(&pb, 1, 1); /* non constrainted bit stream */ put_bits(&pb, 1, 0); /* audio locked */ put_bits(&pb, 1, 0); /* video locked */ put_bits(&pb, 1, 1); /* marker */ put_bits(&pb, 5, s->video_bound); put_bits(&pb, 8, 0xff); /* reserved byte */ /* audio stream info */ private_stream_coded = 0; for(i=0;i<ctx->nb_streams;i++) { StreamInfo *stream = ctx->streams[i]->priv_data; id = stream->id; if (id < 0xc0) { /* special case for private streams (AC3 use that) */ if (private_stream_coded) continue; private_stream_coded = 1; id = 0xbd; } put_bits(&pb, 8, id); /* stream ID */ put_bits(&pb, 2, 3); if (id < 0xe0) { /* audio */ put_bits(&pb, 1, 0); put_bits(&pb, 13, stream->max_buffer_size / 128); } else { /* video */ put_bits(&pb, 1, 1); put_bits(&pb, 13, stream->max_buffer_size / 1024); } } flush_put_bits(&pb); size = pbBufPtr(&pb) - pb.buf; /* patch packet size */ buf[4] = (size - 6) >> 8; buf[5] = (size - 6) & 0xff; return size;}static int mpeg_mux_init(AVFormatContext *ctx){ MpegMuxContext *s = ctx->priv_data; int bitrate, i, mpa_id, mpv_id, ac3_id; AVStream *st; StreamInfo *stream; s->packet_number = 0; s->is_vcd = (ctx->oformat == &mpeg1vcd_mux); s->is_mpeg2 = (ctx->oformat == &mpeg2vob_mux); if (s->is_vcd) s->packet_size = 2324; /* VCD packet size */ else s->packet_size = 2048; /* startcode(4) + length(2) + flags(1) */ s->packet_data_max_size = s->packet_size - 7; s->audio_bound = 0; s->video_bound = 0; mpa_id = AUDIO_ID; ac3_id = 0x80; mpv_id = VIDEO_ID; for(i=0;i<ctx->nb_streams;i++) { st = ctx->streams[i]; stream = av_mallocz(sizeof(StreamInfo)); if (!stream) goto fail; st->priv_data = stream; switch(st->codec.codec_type) { case CODEC_TYPE_AUDIO: if (st->codec.codec_id == CODEC_ID_AC3) stream->id = ac3_id++; else stream->id = mpa_id++; stream->max_buffer_size = 4 * 1024; s->audio_bound++; break; case CODEC_TYPE_VIDEO: stream->id = mpv_id++; stream->max_buffer_size = 46 * 1024; s->video_bound++; break; default: av_abort(); } } /* we increase slightly the bitrate to take into account the headers. XXX: compute it exactly */ bitrate = 2000; for(i=0;i<ctx->nb_streams;i++) { st = ctx->streams[i]; bitrate += st->codec.bit_rate; } s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); 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) /* every 40 packets, this is my invention */ s->system_header_freq = s->pack_header_freq * 40; 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->buffer_ptr = 0; stream->packet_number = 0; stream->start_pts = -1; } return 0; fail: for(i=0;i<ctx->nb_streams;i++) { av_free(ctx->streams[i]->priv_data); } return -ENOMEM;}/* flush the packet on stream stream_index */static void flush_packet(AVFormatContext *ctx, int stream_index){ MpegMuxContext *s = ctx->priv_data; StreamInfo *stream = ctx->streams[stream_index]->priv_data; uint8_t *buf_ptr; int size, payload_size, startcode, id, len, stuffing_size, i, header_len; int64_t timestamp; uint8_t buffer[128]; id = stream->id; timestamp = stream->start_pts;#if 0 printf("packet ID=%2x PTS=%0.3f\n", id, timestamp / 90000.0);#endif buf_ptr = buffer; if (((s->packet_number % s->pack_header_freq) == 0)) { /* output pack and systems header if needed */ size = put_pack_header(ctx, buf_ptr, timestamp); buf_ptr += size; if ((s->packet_number % s->system_header_freq) == 0) { size = put_system_header(ctx, buf_ptr); buf_ptr += size; } } size = buf_ptr - buffer; put_buffer(&ctx->pb, buffer, size); /* packet header */ if (s->is_mpeg2) { header_len = 8; } else { header_len = 5; } payload_size = s->packet_size - (size + 6 + header_len); if (id < 0xc0) { startcode = PRIVATE_STREAM_1; payload_size -= 4; } else { startcode = 0x100 + id; } stuffing_size = payload_size - stream->buffer_ptr; if (stuffing_size < 0) stuffing_size = 0; put_be32(&ctx->pb, startcode); put_be16(&ctx->pb, payload_size + header_len); /* stuffing */ for(i=0;i<stuffing_size;i++) put_byte(&ctx->pb, 0xff); if (s->is_mpeg2) { put_byte(&ctx->pb, 0x80); /* mpeg2 id */ put_byte(&ctx->pb, 0x80); /* flags */ put_byte(&ctx->pb, 0x05); /* header len (only pts is included) */ } put_byte(&ctx->pb, (0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1); put_be16(&ctx->pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1)); put_be16(&ctx->pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1)); if (startcode == PRIVATE_STREAM_1) { put_byte(&ctx->pb, id); if (id >= 0x80 && id <= 0xbf) { /* XXX: need to check AC3 spec */ put_byte(&ctx->pb, 1); put_byte(&ctx->pb, 0); put_byte(&ctx->pb, 2); } } /* output data */ put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); put_flush_packet(&ctx->pb); /* preserve remaining data */ len = stream->buffer_ptr - payload_size; if (len < 0) len = 0; memmove(stream->buffer, stream->buffer + stream->buffer_ptr - len, len); stream->buffer_ptr = len; s->packet_number++; stream->packet_number++; stream->start_pts = -1;}static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, const uint8_t *buf, int size, int64_t pts){ MpegMuxContext *s = ctx->priv_data; AVStream *st = ctx->streams[stream_index]; StreamInfo *stream = st->priv_data; int len; while (size > 0) { /* set pts */ if (stream->start_pts == -1) { stream->start_pts = pts;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -