av_log(s, AV_LOG_WARNING,
"Codec for stream %d does not use global headers "
"but container format requires global headers\n", i);
+
+ if (codec->codec_type != AVMEDIA_TYPE_ATTACHMENT)
+ s->internal->nb_interleaved_streams++;
}
if (!s->priv_data && of->priv_data_size > 0) {
return 0;
}
+#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))
+
+
//FIXME merge with compute_pkt_fields
static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
/* update pts */
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- frame_size = ff_get_audio_frame_size(st->codec, pkt->size, 1);
+ frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
+ ((AVFrame *)pkt->data)->nb_samples :
+ ff_get_audio_frame_size(st->codec, pkt->size, 1);
/* HACK/FIXME, we skip the initial 0 size packets as they are most
* likely equal to the encoder delay, but it would be better if we
}
did_split = av_packet_split_side_data(pkt);
- ret = s->oformat->write_packet(s, 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);
+ } else {
+ ret = s->oformat->write_packet(s, pkt);
+ }
if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);
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);
+ return AVERROR(EINVAL);
+ }
+
+ if (s->streams[pkt->stream_index]->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) {
+ av_log(s, AV_LOG_ERROR, "Received a packet for an attachment stream.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
{
int ret;
+ ret = check_packet(s, pkt);
+ if (ret < 0)
+ return ret;
+
if (!pkt) {
if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
ret = s->oformat->write_packet(s, NULL);
FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->buf = NULL;
- av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-allocated memory
- av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data
+ if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
+ av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
+ av_assert0(((AVFrame *)pkt->data)->buf);
+ } else {
+ av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-allocated memory
+ av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data
+ }
if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
next_point = &(st->last_in_packet_buffer->next);
{
AVPacketList *pktl;
int stream_count = 0, noninterleaved_count = 0;
- int64_t delta_dts_max = 0;
int i, ret;
if (pkt) {
}
}
- if (s->nb_streams == stream_count) {
+ if (s->internal->nb_interleaved_streams == stream_count)
flush = 1;
- } else if (!flush) {
- for (i=0; i < s->nb_streams; i++) {
- if (s->streams[i]->last_in_packet_buffer) {
- int64_t delta_dts =
- av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts,
- s->streams[i]->time_base,
- AV_TIME_BASE_Q) -
- av_rescale_q(s->packet_buffer->pkt.dts,
- s->streams[s->packet_buffer->pkt.stream_index]->time_base,
- AV_TIME_BASE_Q);
- delta_dts_max= FFMAX(delta_dts_max, delta_dts);
- }
+
+ if (s->max_interleave_delta > 0 && s->packet_buffer && !flush) {
+ AVPacket *top_pkt = &s->packet_buffer->pkt;
+ int64_t delta_dts = INT64_MIN;
+ int64_t top_dts = av_rescale_q(top_pkt->dts,
+ s->streams[top_pkt->stream_index]->time_base,
+ AV_TIME_BASE_Q);
+
+ for (i = 0; i < s->nb_streams; i++) {
+ int64_t last_dts;
+ const AVPacketList *last = s->streams[i]->last_in_packet_buffer;
+
+ if (!last)
+ continue;
+
+ last_dts = av_rescale_q(last->pkt.dts,
+ s->streams[i]->time_base,
+ AV_TIME_BASE_Q);
+ delta_dts = FFMAX(delta_dts, last_dts - top_dts);
}
- if (s->nb_streams == stream_count+noninterleaved_count &&
- delta_dts_max > 20*AV_TIME_BASE) {
- av_log(s, AV_LOG_DEBUG, "flushing with %d noninterleaved\n", noninterleaved_count);
+
+ if (delta_dts > s->max_interleave_delta) {
+ av_log(s, AV_LOG_DEBUG,
+ "Delay between the first packet and last packet in the "
+ "muxing queue is %"PRId64" > %"PRId64": forcing output\n",
+ delta_dts, s->max_interleave_delta);
flush = 1;
}
}
+
if (stream_count && flush) {
AVStream *st;
pktl = s->packet_buffer;
{
int ret, flush = 0;
+ ret = check_packet(s, pkt);
+ if (ret < 0)
+ goto fail;
+
if (pkt) {
AVStream *st = s->streams[pkt->stream_index];
//FIXME/XXX/HACK drop zero sized packets
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->size == 0)
- return 0;
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->size == 0) {
+ ret = 0;
+ goto fail;
+ }
av_dlog(s, "av_interleaved_write_frame size:%d dts:%s pts:%s\n",
pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts));
if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
- return ret;
+ goto fail;
- if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
- return AVERROR(EINVAL);
+ if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
} else {
av_dlog(s, "av_interleaved_write_frame FLUSH\n");
flush = 1;
for (;; ) {
AVPacket opkt;
int ret = interleave_packet(s, &opkt, pkt, flush);
+ if (pkt) {
+ memset(pkt, 0, sizeof(*pkt));
+ av_init_packet(pkt);
+ pkt = NULL;
+ }
if (ret <= 0) //FIXME cleanup needed for ret<0 ?
return ret;
s->streams[opkt.stream_index]->nb_frames++;
av_free_packet(&opkt);
- pkt = NULL;
if (ret < 0)
return ret;
if(s->pb && s->pb->error)
return s->pb->error;
}
+fail:
+ av_packet_unref(pkt);
+ return ret;
}
int av_write_trailer(AVFormatContext *s)
dst->streams[dst_stream]->time_base);
return av_write_frame(dst, &local_pkt);
}
+
+static int av_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)
+ return AVERROR(ENOSYS);
+
+ if (!frame) {
+ pktp = NULL;
+ } else {
+ pktp = &pkt;
+ av_init_packet(&pkt);
+ pkt.data = (void *)frame;
+ pkt.size = UNCODED_FRAME_PACKET_SIZE;
+ pkt.pts =
+ pkt.dts = frame->pts;
+ pkt.duration = av_frame_get_pkt_duration(frame);
+ pkt.stream_index = stream_index;
+ pkt.flags |= AV_PKT_FLAG_UNCODED_FRAME;
+ }
+
+ return interleaved ? av_interleaved_write_frame(s, pktp) :
+ av_write_frame(s, pktp);
+}
+
+int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
+ AVFrame *frame)
+{
+ return av_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);
+}
+
+int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)
+{
+ av_assert0(s->oformat);
+ if (!s->oformat->write_uncoded_frame)
+ return AVERROR(ENOSYS);
+ return s->oformat->write_uncoded_frame(s, stream_index, NULL,
+ AV_WRITE_UNCODED_FRAME_QUERY);
+}