... | ... |
@@ -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 |
+} |