Browse code

lavf: add write_uncoded_frame() API.

Nicolas George authored on 2013/12/31 22:09:48
Showing 3 changed files
... ...
@@ -512,6 +512,17 @@ typedef struct AVOutputFormat {
512 512
      */
513 513
     int (*control_message)(struct AVFormatContext *s, int type,
514 514
                            void *data, size_t data_size);
515
+
516
+    /**
517
+     * Write an uncoded AVFrame.
518
+     *
519
+     * See av_write_uncoded_frame() for details.
520
+     *
521
+     * The library will free *frame afterwards, but the muxer can prevent it
522
+     * by setting the pointer to NULL.
523
+     */
524
+    int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index,
525
+                               AVFrame **frame, unsigned flags);
515 526
 } AVOutputFormat;
516 527
 /**
517 528
  * @}
... ...
@@ -2093,6 +2104,44 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt);
2093 2093
 int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
2094 2094
 
2095 2095
 /**
2096
+ * Write a uncoded frame to an output media file.
2097
+ *
2098
+ * The frame must be correctly interleaved according to the container
2099
+ * specification; if not, then av_interleaved_write_frame() must be used.
2100
+ *
2101
+ * See av_interleaved_write_frame() for details.
2102
+ */
2103
+int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
2104
+                           AVFrame *frame);
2105
+
2106
+/**
2107
+ * Write a uncoded frame to an output media file.
2108
+ *
2109
+ * If the muxer supports it, this function allows to write an AVFrame
2110
+ * structure directly, without encoding it into a packet.
2111
+ * It is mostly useful for devices and similar special muxers that use raw
2112
+ * video or PCM data and will not serialize it into a byte stream.
2113
+ *
2114
+ * To test whether it is possible to use it with a given muxer and stream,
2115
+ * use av_write_uncoded_frame_query().
2116
+ *
2117
+ * The caller gives up ownership of the frame and must not access it
2118
+ * afterwards.
2119
+ *
2120
+ * @return  >=0 for success, a negative code on error
2121
+ */
2122
+int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
2123
+                                       AVFrame *frame);
2124
+
2125
+/**
2126
+ * Test whether a muxer supports uncoded frame.
2127
+ *
2128
+ * @return  >=0 if an uncoded frame can be written to that muxer and stream,
2129
+ *          <0 if not
2130
+ */
2131
+int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index);
2132
+
2133
+/**
2096 2134
  * Write the stream trailer to an output media file and free the
2097 2135
  * file private data.
2098 2136
  *
... ...
@@ -398,4 +398,18 @@ int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts);
398 398
 
399 399
 void ff_rfps_calculate(AVFormatContext *ic);
400 400
 
401
+/**
402
+ * Flags for AVFormatContext.write_uncoded_frame()
403
+ */
404
+enum AVWriteUncodedFrameFlags {
405
+
406
+    /**
407
+     * Query whether the feature is possible on this stream.
408
+     * The frame argument is ignored.
409
+     */
410
+    AV_WRITE_UNCODED_FRAME_QUERY           = 0x0001,
411
+
412
+};
413
+
414
+
401 415
 #endif /* AVFORMAT_INTERNAL_H */
... ...
@@ -417,6 +417,15 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
417 417
     return 0;
418 418
 }
419 419
 
420
+#define AV_PKT_FLAG_UNCODED_FRAME 0x2000
421
+
422
+/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but
423
+   it is only being used internally to this file as a consistency check.
424
+   The value is chosen to be very unlikely to appear on its own and to cause
425
+   immediate failure if used anywhere as a real size. */
426
+#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame))
427
+
428
+
420 429
 //FIXME merge with compute_pkt_fields
421 430
 static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
422 431
 {
... ...
@@ -482,7 +491,9 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
482 482
     /* update pts */
483 483
     switch (st->codec->codec_type) {
484 484
     case AVMEDIA_TYPE_AUDIO:
485
-        frame_size = ff_get_audio_frame_size(st->codec, pkt->size, 1);
485
+        frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
486
+                     ((AVFrame *)pkt->data)->nb_samples :
487
+                     ff_get_audio_frame_size(st->codec, pkt->size, 1);
486 488
 
487 489
         /* HACK/FIXME, we skip the initial 0 size packets as they are most
488 490
          * likely equal to the encoder delay, but it would be better if we
... ...
@@ -549,7 +560,14 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt)
549 549
     }
550 550
 
551 551
     did_split = av_packet_split_side_data(pkt);
552
-    ret = s->oformat->write_packet(s, pkt);
552
+    if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
553
+        AVFrame *frame = (AVFrame *)pkt->data;
554
+        av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
555
+        ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0);
556
+        av_frame_free(&frame);
557
+    } else {
558
+        ret = s->oformat->write_packet(s, pkt);
559
+    }
553 560
 
554 561
     if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
555 562
         avio_flush(s->pb);
... ...
@@ -632,8 +650,13 @@ FF_DISABLE_DEPRECATION_WARNINGS
632 632
 FF_ENABLE_DEPRECATION_WARNINGS
633 633
 #endif
634 634
     pkt->buf       = NULL;
635
-    av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-allocated memory
636
-    av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data
635
+    if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
636
+        av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
637
+        av_assert0(((AVFrame *)pkt->data)->buf);
638
+    } else {
639
+        av_dup_packet(&this_pktl->pkt);  // duplicate the packet if it uses non-allocated memory
640
+        av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data
641
+    }
637 642
 
638 643
     if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
639 644
         next_point = &(st->last_in_packet_buffer->next);
... ...
@@ -932,3 +955,51 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
932 932
                                           dst->streams[dst_stream]->time_base);
933 933
     return av_write_frame(dst, &local_pkt);
934 934
 }
935
+
936
+static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
937
+                                           AVFrame *frame, int interleaved)
938
+{
939
+    AVPacket pkt, *pktp;
940
+
941
+    av_assert0(s->oformat);
942
+    if (!s->oformat->write_uncoded_frame)
943
+        return AVERROR(ENOSYS);
944
+
945
+    if (!frame) {
946
+        pktp = NULL;
947
+    } else {
948
+        pktp = &pkt;
949
+        av_init_packet(&pkt);
950
+        pkt.data = (void *)frame;
951
+        pkt.size         = UNCODED_FRAME_PACKET_SIZE;
952
+        pkt.pts          =
953
+        pkt.dts          = frame->pts;
954
+        pkt.duration     = av_frame_get_pkt_duration(frame);
955
+        pkt.stream_index = stream_index;
956
+        pkt.flags |= AV_PKT_FLAG_UNCODED_FRAME;
957
+    }
958
+
959
+    return interleaved ? av_interleaved_write_frame(s, pktp) :
960
+                         av_write_frame(s, pktp);
961
+}
962
+
963
+int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
964
+                           AVFrame *frame)
965
+{
966
+    return av_write_uncoded_frame_internal(s, stream_index, frame, 0);
967
+}
968
+
969
+int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
970
+                                       AVFrame *frame)
971
+{
972
+    return av_write_uncoded_frame_internal(s, stream_index, frame, 1);
973
+}
974
+
975
+int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)
976
+{
977
+    av_assert0(s->oformat);
978
+    if (!s->oformat->write_uncoded_frame)
979
+        return AVERROR(ENOSYS);
980
+    return s->oformat->write_uncoded_frame(s, stream_index, NULL,
981
+                                           AV_WRITE_UNCODED_FRAME_QUERY);
982
+}