]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mpegenc.c
avcodec/mjpegdec: fix SOF check in EOI
[ffmpeg] / libavformat / mpegenc.c
index 4c6fa67fb83c163c2589c1e4561a65dfbcbef70d..93c4920904325b0d779a6b34a3a267e5e3c4fa1a 100644 (file)
@@ -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