X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmpegenc.c;h=93c4920904325b0d779a6b34a3a267e5e3c4fa1a;hb=bc70684e74a185d7b80c8b80bdedda659cb581b8;hp=4c6fa67fb83c163c2589c1e4561a65dfbcbef70d;hpb=03210fe138f3b3bd7f5272fe29aca810cf517329;p=ffmpeg diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c index 4c6fa67fb83..93c49209043 100644 --- a/libavformat/mpegenc.c +++ b/libavformat/mpegenc.c @@ -48,9 +48,9 @@ typedef struct StreamInfo { uint8_t id; int max_buffer_size; /* in bytes */ int buffer_index; - PacketDesc *predecode_packet; + PacketDesc *predecode_packet; /* start of packet queue */ + PacketDesc *last_packet; /* end of packet queue */ PacketDesc *premux_packet; - PacketDesc **next_packet; int packet_number; uint8_t lpcm_header[3]; int lpcm_align; @@ -83,10 +83,10 @@ typedef struct MpegMuxContext { int preload; } MpegMuxContext; -extern AVOutputFormat ff_mpeg1vcd_muxer; -extern AVOutputFormat ff_mpeg2dvd_muxer; -extern AVOutputFormat ff_mpeg2svcd_muxer; -extern AVOutputFormat ff_mpeg2vob_muxer; +extern const AVOutputFormat ff_mpeg1vcd_muxer; +extern const AVOutputFormat ff_mpeg2dvd_muxer; +extern const AVOutputFormat ff_mpeg2svcd_muxer; +extern const AVOutputFormat ff_mpeg2vob_muxer; static int put_pack_header(AVFormatContext *ctx, uint8_t *buf, int64_t timestamp) @@ -315,7 +315,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) if (ctx->packet_size < 20 || ctx->packet_size > (1 << 23) + 10) { av_log(ctx, AV_LOG_ERROR, "Invalid packet size %d\n", ctx->packet_size); - goto fail; + return AVERROR(EINVAL); } s->packet_size = ctx->packet_size; } else @@ -343,7 +343,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) st = ctx->streams[i]; stream = av_mallocz(sizeof(StreamInfo)); if (!stream) - goto fail; + return AVERROR(ENOMEM); st->priv_data = stream; avpriv_set_pts_info(st, 64, 1, 90000); @@ -364,12 +364,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->id = ac3_id++; } else if (st->codecpar->codec_id == AV_CODEC_ID_DTS) { stream->id = dts_id++; - } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE || - st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { - if (st->codecpar->bits_per_coded_sample != 16) { - av_log(ctx, AV_LOG_ERROR, "Only 16 bit LPCM streams can be muxed.\n"); - goto fail; - } + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE) { stream->id = lpcm_id++; for (j = 0; j < 4; j++) { if (lpcm_freq_tab[j] == st->codecpar->sample_rate) @@ -382,16 +377,46 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) for (sr = 0; sr < 4; sr++) av_log(ctx, AV_LOG_INFO, " %d", lpcm_freq_tab[sr]); av_log(ctx, AV_LOG_INFO, "\n"); - goto fail; + return AVERROR(EINVAL); } if (st->codecpar->channels > 8) { av_log(ctx, AV_LOG_ERROR, "At most 8 channels allowed for LPCM streams.\n"); - goto fail; + return AVERROR(EINVAL); } stream->lpcm_header[0] = 0x0c; stream->lpcm_header[1] = (st->codecpar->channels - 1) | (j << 4); stream->lpcm_header[2] = 0x80; stream->lpcm_align = st->codecpar->channels * 2; + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { + int freq; + + switch (st->codecpar->sample_rate) { + case 48000: freq = 0; break; + case 96000: freq = 1; break; + case 44100: freq = 2; break; + case 32000: freq = 3; break; + default: + av_log(ctx, AV_LOG_ERROR, "Unsupported sample rate.\n"); + return AVERROR(EINVAL); + } + + stream->lpcm_header[0] = 0x0c; + stream->lpcm_header[1] = (freq << 4) | + (((st->codecpar->bits_per_coded_sample - 16) / 4) << 6) | + st->codecpar->channels - 1; + stream->lpcm_header[2] = 0x80; + stream->id = lpcm_id++; + stream->lpcm_align = st->codecpar->channels * st->codecpar->bits_per_coded_sample / 8; + } else if (st->codecpar->codec_id == AV_CODEC_ID_MLP || + st->codecpar->codec_id == AV_CODEC_ID_TRUEHD) { + av_log(ctx, AV_LOG_ERROR, "Support for muxing audio codec %s not implemented.\n", + avcodec_get_name(st->codecpar->codec_id)); + return AVERROR_PATCHWELCOME; + } else if (st->codecpar->codec_id != AV_CODEC_ID_MP1 && + st->codecpar->codec_id != AV_CODEC_ID_MP2 && + st->codecpar->codec_id != AV_CODEC_ID_MP3) { + av_log(ctx, AV_LOG_ERROR, "Unsupported audio codec. Must be one of mp1, mp2, mp3, 16-bit pcm_dvd, pcm_s16be, ac3 or dts.\n"); + return AVERROR(EINVAL); } else { stream->id = mpa_id++; } @@ -435,7 +460,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) } stream->fifo = av_fifo_alloc(16); if (!stream->fifo) - goto fail; + return AVERROR(ENOMEM); } bitrate = 0; audio_bitrate = 0; @@ -535,11 +560,6 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) s->system_header_size = get_system_header_size(ctx); s->last_scr = AV_NOPTS_VALUE; return 0; - -fail: - for (i = 0; i < ctx->nb_streams; i++) - av_freep(&ctx->streams[i]->priv_data); - return AVERROR(ENOMEM); } static inline void put_timestamp(AVIOContext *pb, int id, int64_t timestamp) @@ -908,7 +928,7 @@ static int flush_packet(AVFormatContext *ctx, int stream_index, for (i = 0; i < zero_trail_bytes; i++) avio_w8(ctx->pb, 0x00); - avio_flush(ctx->pb); + avio_write_marker(ctx->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); s->packet_number++; @@ -937,7 +957,7 @@ static void put_vcd_padding_sector(AVFormatContext *ctx) s->vcd_padding_bytes_written += s->packet_size; - avio_flush(ctx->pb); + avio_write_marker(ctx->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT); /* increasing the packet number is correct. The SCR of the following packs * is calculated from the packet_number and it has to include the padding @@ -966,6 +986,8 @@ static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr) } stream->buffer_index -= pkt_desc->size; stream->predecode_packet = pkt_desc->next; + if (!stream->predecode_packet) + stream->last_packet = NULL; av_freep(&pkt_desc); } } @@ -1129,7 +1151,7 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) StreamInfo *stream = st->priv_data; int64_t pts, dts; PacketDesc *pkt_desc; - int preload; + int preload, ret; const int is_iframe = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY); @@ -1157,14 +1179,6 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) av_log(ctx, AV_LOG_TRACE, "dts:%f pts:%f flags:%d stream:%d nopts:%d\n", dts / 90000.0, pts / 90000.0, pkt->flags, pkt->stream_index, pts != AV_NOPTS_VALUE); - if (!stream->premux_packet) - stream->next_packet = &stream->premux_packet; - *stream->next_packet = - pkt_desc = av_mallocz(sizeof(PacketDesc)); - if (!pkt_desc) - return AVERROR(ENOMEM); - pkt_desc->pts = pts; - pkt_desc->dts = dts; if (st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { if (size < 3) { @@ -1178,19 +1192,29 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) size -= 3; } + pkt_desc = av_mallocz(sizeof(PacketDesc)); + if (!pkt_desc) + return AVERROR(ENOMEM); + if (!stream->predecode_packet) { + stream->predecode_packet = pkt_desc; + } else + stream->last_packet->next = pkt_desc; + stream->last_packet = pkt_desc; + if (!stream->premux_packet) + stream->premux_packet = pkt_desc; + pkt_desc->pts = pts; + pkt_desc->dts = dts; pkt_desc->unwritten_size = pkt_desc->size = size; - if (!stream->predecode_packet) - stream->predecode_packet = pkt_desc; - stream->next_packet = &pkt_desc->next; - if (av_fifo_realloc2(stream->fifo, av_fifo_size(stream->fifo) + size) < 0) - return -1; + ret = av_fifo_realloc2(stream->fifo, av_fifo_size(stream->fifo) + size); + if (ret < 0) + return ret; if (s->is_dvd) { // min VOBU length 0.4 seconds (mpucoder) if (is_iframe && - (s->packet_number == 0 || + (s->packet_number == 0 || pts != AV_NOPTS_VALUE && (pts - stream->vobu_start_pts >= 36000))) { stream->bytes_to_iframe = av_fifo_size(stream->fifo); stream->align_iframe = 1; @@ -1224,17 +1248,30 @@ static int mpeg_mux_end(AVFormatContext *ctx) * it as it is usually not needed by decoders and because it * complicates MPEG stream concatenation. */ // avio_wb32(ctx->pb, ISO_11172_END_CODE); - // avio_flush(ctx->pb); for (i = 0; i < ctx->nb_streams; i++) { stream = ctx->streams[i]->priv_data; av_assert0(av_fifo_size(stream->fifo) == 0); - av_fifo_freep(&stream->fifo); } return 0; } +static void mpeg_mux_deinit(AVFormatContext *ctx) +{ + for (int i = 0; i < ctx->nb_streams; i++) { + StreamInfo *stream = ctx->streams[i]->priv_data; + if (!stream) + continue; + for (PacketDesc *pkt = stream->predecode_packet; pkt; ) { + PacketDesc *tmp = pkt->next; + av_free(pkt); + pkt = tmp; + } + av_fifo_freep(&stream->fifo); + } +} + #define OFFSET(x) offsetof(MpegMuxContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -1253,7 +1290,7 @@ static const AVClass flavor ## _class = { \ #if CONFIG_MPEG1SYSTEM_MUXER MPEGENC_CLASS(mpeg) -AVOutputFormat ff_mpeg1system_muxer = { +const AVOutputFormat ff_mpeg1system_muxer = { .name = "mpeg", .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 Systems / MPEG program stream"), .mime_type = "video/mpeg", @@ -1264,13 +1301,14 @@ AVOutputFormat ff_mpeg1system_muxer = { .write_header = mpeg_mux_init, .write_packet = mpeg_mux_write_packet, .write_trailer = mpeg_mux_end, + .deinit = mpeg_mux_deinit, .priv_class = &mpeg_class, }; #endif #if CONFIG_MPEG1VCD_MUXER MPEGENC_CLASS(vcd) -AVOutputFormat ff_mpeg1vcd_muxer = { +const AVOutputFormat ff_mpeg1vcd_muxer = { .name = "vcd", .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 Systems / MPEG program stream (VCD)"), .mime_type = "video/mpeg", @@ -1280,13 +1318,14 @@ AVOutputFormat ff_mpeg1vcd_muxer = { .write_header = mpeg_mux_init, .write_packet = mpeg_mux_write_packet, .write_trailer = mpeg_mux_end, + .deinit = mpeg_mux_deinit, .priv_class = &vcd_class, }; #endif #if CONFIG_MPEG2VOB_MUXER MPEGENC_CLASS(vob) -AVOutputFormat ff_mpeg2vob_muxer = { +const AVOutputFormat ff_mpeg2vob_muxer = { .name = "vob", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 PS (VOB)"), .mime_type = "video/mpeg", @@ -1297,6 +1336,7 @@ AVOutputFormat ff_mpeg2vob_muxer = { .write_header = mpeg_mux_init, .write_packet = mpeg_mux_write_packet, .write_trailer = mpeg_mux_end, + .deinit = mpeg_mux_deinit, .priv_class = &vob_class, }; #endif @@ -1304,7 +1344,7 @@ AVOutputFormat ff_mpeg2vob_muxer = { /* Same as mpeg2vob_mux except that the pack size is 2324 */ #if CONFIG_MPEG2SVCD_MUXER MPEGENC_CLASS(svcd) -AVOutputFormat ff_mpeg2svcd_muxer = { +const AVOutputFormat ff_mpeg2svcd_muxer = { .name = "svcd", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 PS (SVCD)"), .mime_type = "video/mpeg", @@ -1315,6 +1355,7 @@ AVOutputFormat ff_mpeg2svcd_muxer = { .write_header = mpeg_mux_init, .write_packet = mpeg_mux_write_packet, .write_trailer = mpeg_mux_end, + .deinit = mpeg_mux_deinit, .priv_class = &svcd_class, }; #endif @@ -1322,7 +1363,7 @@ AVOutputFormat ff_mpeg2svcd_muxer = { /* Same as mpeg2vob_mux except the 'is_dvd' flag is set to produce NAV pkts */ #if CONFIG_MPEG2DVD_MUXER MPEGENC_CLASS(dvd) -AVOutputFormat ff_mpeg2dvd_muxer = { +const AVOutputFormat ff_mpeg2dvd_muxer = { .name = "dvd", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 PS (DVD VOB)"), .mime_type = "video/mpeg", @@ -1333,6 +1374,7 @@ AVOutputFormat ff_mpeg2dvd_muxer = { .write_header = mpeg_mux_init, .write_packet = mpeg_mux_write_packet, .write_trailer = mpeg_mux_end, + .deinit = mpeg_mux_deinit, .priv_class = &dvd_class, }; #endif