]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mux.c
avformat/mux: Make uncoded frames av_packet_unref() compatible
[ffmpeg] / libavformat / mux.c
index a06d98305965a29c2f22acb2918666d440cf12bd..bb54fd5528f57bdc37ca29fae7d434f563140641 100644 (file)
@@ -550,12 +550,6 @@ fail:
 
 #define AV_PKT_FLAG_UNCODED_FRAME 0x2000
 
-/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but
-   it is only being used internally to this file as a consistency check.
-   The value is chosen to be very unlikely to appear on its own and to cause
-   immediate failure if used anywhere as a real size. */
-#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame))
-
 
 #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -650,7 +644,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket *
     switch (st->codecpar->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
         frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
-                     ((AVFrame *)pkt->data)->nb_samples :
+                     (*(AVFrame **)pkt->data)->nb_samples :
                      av_get_audio_frame_duration(st->codec, pkt->size);
 
         /* HACK/FIXME, we skip the initial 0 size packets as they are most
@@ -746,10 +740,10 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
-        AVFrame *frame = (AVFrame *)pkt->data;
-        av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
-        ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0);
-        av_frame_free(&frame);
+        AVFrame **frame = (AVFrame **)pkt->data;
+        av_assert0(pkt->size == sizeof(*frame));
+        ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, frame, 0);
+        av_packet_unref(pkt);
     } else {
         ret = s->oformat->write_packet(s, pkt);
     }
@@ -763,16 +757,14 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
     if (ret < 0) {
         pkt->pts = pts_backup;
         pkt->dts = dts_backup;
-    }
+    } else
+        s->streams[pkt->stream_index]->nb_frames++;
 
     return ret;
 }
 
 static int check_packet(AVFormatContext *s, AVPacket *pkt)
 {
-    if (!pkt)
-        return 0;
-
     if (pkt->stream_index < 0 || pkt->stream_index >= s->nb_streams) {
         av_log(s, AV_LOG_ERROR, "Invalid packet stream index: %d\n",
                pkt->stream_index);
@@ -886,10 +878,6 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
 {
     int ret;
 
-    ret = prepare_input_packet(s, pkt);
-    if (ret < 0)
-        return ret;
-
     if (!pkt) {
         if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
             ret = s->oformat->write_packet(s, NULL);
@@ -901,6 +889,10 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
         return 1;
     }
 
+    ret = prepare_input_packet(s, pkt);
+    if (ret < 0)
+        return ret;
+
     ret = do_packet_auto_bsf(s, pkt);
     if (ret <= 0)
         return ret;
@@ -912,13 +904,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
         return ret;
 #endif
 
-    ret = write_packet(s, pkt);
-    if (ret >= 0 && s->pb && s->pb->error < 0)
-        ret = s->pb->error;
-
-    if (ret >= 0)
-        s->streams[pkt->stream_index]->nb_frames++;
-    return ret;
+    return write_packet(s, pkt);
 }
 
 #define CHUNK_START 0x1000
@@ -928,26 +914,21 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
 {
     int ret;
     AVPacketList **next_point, *this_pktl;
-    AVStream *st   = s->streams[pkt->stream_index];
-    int chunked    = s->max_chunk_size || s->max_chunk_duration;
+    AVStream *st = s->streams[pkt->stream_index];
+    int chunked  = s->max_chunk_size || s->max_chunk_duration;
 
-    this_pktl      = av_malloc(sizeof(AVPacketList));
+    this_pktl    = av_malloc(sizeof(AVPacketList));
     if (!this_pktl)
         return AVERROR(ENOMEM);
-    if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
-        av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
-        av_assert0(((AVFrame *)pkt->data)->buf);
-    } else {
-        if ((ret = av_packet_make_refcounted(pkt)) < 0) {
-            av_free(this_pktl);
-            return ret;
-        }
+    if ((ret = av_packet_make_refcounted(pkt)) < 0) {
+        av_free(this_pktl);
+        return ret;
     }
 
     av_packet_move_ref(&this_pktl->pkt, pkt);
     pkt = &this_pktl->pkt;
 
-    if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
+    if (st->last_in_packet_buffer) {
         next_point = &(st->last_in_packet_buffer->next);
     } else {
         next_point = &s->internal->packet_buffer;
@@ -959,8 +940,8 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
         st->interleaver_chunk_duration += pkt->duration;
         if (   (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size)
             || (max && st->interleaver_chunk_duration           > max)) {
-            st->interleaver_chunk_size      = 0;
-            this_pktl->pkt.flags |= CHUNK_START;
+            st->interleaver_chunk_size = 0;
+            pkt->flags |= CHUNK_START;
             if (max && st->interleaver_chunk_duration > max) {
                 int64_t syncoffset = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)*max/2;
                 int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset;
@@ -971,7 +952,7 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
         }
     }
     if (*next_point) {
-        if (chunked && !(this_pktl->pkt.flags & CHUNK_START))
+        if (chunked && !(pkt->flags & CHUNK_START))
             goto next_non_null;
 
         if (compare(s, &s->internal->packet_buffer_end->pkt, pkt)) {
@@ -992,8 +973,7 @@ next_non_null:
 
     this_pktl->next = *next_point;
 
-    s->streams[pkt->stream_index]->last_in_packet_buffer =
-        *next_point                                      = this_pktl;
+    st->last_in_packet_buffer = *next_point = this_pktl;
 
     return 0;
 }
@@ -1197,13 +1177,13 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
 {
     int ret, flush = 0;
 
-    ret = prepare_input_packet(s, pkt);
-    if (ret < 0)
-        goto fail;
-
     if (pkt) {
         AVStream *st = s->streams[pkt->stream_index];
 
+        ret = prepare_input_packet(s, pkt);
+        if (ret < 0)
+            goto fail;
+
         ret = do_packet_auto_bsf(s, pkt);
         if (ret == 0)
             return 0;
@@ -1240,15 +1220,11 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
             return ret;
 
         ret = write_packet(s, &opkt);
-        if (ret >= 0)
-            s->streams[opkt.stream_index]->nb_frames++;
 
         av_packet_unref(&opkt);
 
         if (ret < 0)
             return ret;
-        if(s->pb && s->pb->error)
-            return s->pb->error;
     }
 fail:
     av_packet_unref(pkt);
@@ -1268,15 +1244,11 @@ int av_write_trailer(AVFormatContext *s)
             break;
 
         ret = write_packet(s, &pkt);
-        if (ret >= 0)
-            s->streams[pkt.stream_index]->nb_frames++;
 
         av_packet_unref(&pkt);
 
         if (ret < 0)
             goto fail;
-        if(s->pb && s->pb->error)
-            goto fail;
     }
 
 fail:
@@ -1336,22 +1308,45 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
     return ret;
 }
 
-static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
-                                           AVFrame *frame, int interleaved)
+static void uncoded_frame_free(void *unused, uint8_t *data)
+{
+    av_frame_free((AVFrame **)data);
+    av_free(data);
+}
+
+static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
+                                        AVFrame *frame, int interleaved)
 {
     AVPacket pkt, *pktp;
 
     av_assert0(s->oformat);
-    if (!s->oformat->write_uncoded_frame)
+    if (!s->oformat->write_uncoded_frame) {
+        av_frame_free(&frame);
         return AVERROR(ENOSYS);
+    }
 
     if (!frame) {
         pktp = NULL;
     } else {
+        size_t   bufsize = sizeof(frame) + AV_INPUT_BUFFER_PADDING_SIZE;
+        AVFrame **framep = av_mallocz(bufsize);
+
+        if (!framep)
+            goto fail;
         pktp = &pkt;
         av_init_packet(&pkt);
-        pkt.data = (void *)frame;
-        pkt.size         = UNCODED_FRAME_PACKET_SIZE;
+        pkt.buf = av_buffer_create((void *)framep, bufsize,
+                                   uncoded_frame_free, NULL, 0);
+        if (!pkt.buf) {
+            av_free(framep);
+    fail:
+            av_frame_free(&frame);
+            return AVERROR(ENOMEM);
+        }
+        *framep = frame;
+
+        pkt.data         = (void *)framep;
+        pkt.size         = sizeof(frame);
         pkt.pts          =
         pkt.dts          = frame->pts;
         pkt.duration     = frame->pkt_duration;
@@ -1366,13 +1361,13 @@ static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
 int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
                            AVFrame *frame)
 {
-    return av_write_uncoded_frame_internal(s, stream_index, frame, 0);
+    return write_uncoded_frame_internal(s, stream_index, frame, 0);
 }
 
 int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
                                        AVFrame *frame)
 {
-    return av_write_uncoded_frame_internal(s, stream_index, frame, 1);
+    return write_uncoded_frame_internal(s, stream_index, frame, 1);
 }
 
 int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)