* MOV, 3GP, MP4 muxer RTP hinting
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
*
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * FFmpeg is distributed in the hope that it will be useful,
+ * Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
+ * License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intreadwrite.h"
#include "internal.h"
#include "rtpenc_chain.h"
+#include "avio_internal.h"
+#include "rtp.h"
int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index)
{
track->tag = MKTAG('r','t','p',' ');
track->src_track = src_index;
- track->enc = avcodec_alloc_context();
+ track->enc = avcodec_alloc_context3(NULL);
if (!track->enc)
goto fail;
track->enc->codec_type = AVMEDIA_TYPE_DATA;
track->enc->codec_tag = track->tag;
- track->rtp_ctx = ff_rtp_chain_mux_open(s, src_st, NULL,
- RTP_MAX_PACKET_SIZE);
- if (!track->rtp_ctx)
+ ret = ff_rtp_chain_mux_open(&track->rtp_ctx, s, src_st, NULL,
+ RTP_MAX_PACKET_SIZE, src_index);
+ if (ret < 0)
goto fail;
/* Copy the RTP AVStream timebase back to the hint AVStream */
if (queue->samples[i].own_data)
av_free(queue->samples[i].data);
av_freep(&queue->samples);
- queue->len = 0;
+ queue->len = 0;
queue->size = 0;
}
* not copied. sample_queue_retain should be called before pkt->data
* is reused/freed.
*/
-static void sample_queue_push(HintSampleQueue *queue, AVPacket *pkt, int sample)
+static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size,
+ int sample)
{
/* No need to keep track of smaller samples, since describing them
* with immediates is more efficient. */
- if (pkt->size <= 14)
+ if (size <= 14)
return;
if (!queue->samples || queue->len >= queue->size) {
- HintSample* samples;
queue->size += 10;
- samples = av_realloc(queue->samples, sizeof(HintSample)*queue->size);
- if (!samples)
+ if (av_reallocp(&queue->samples, sizeof(*queue->samples) * queue->size) < 0) {
+ queue->len = queue->size = 0;
return;
- queue->samples = samples;
+ }
}
- queue->samples[queue->len].data = pkt->data;
- queue->samples[queue->len].size = pkt->size;
+ queue->samples[queue->len].data = data;
+ queue->samples[queue->len].size = size;
queue->samples[queue->len].sample_number = sample;
- queue->samples[queue->len].offset = 0;
+ queue->samples[queue->len].offset = 0;
queue->samples[queue->len].own_data = 0;
queue->len++;
}
for (i = 0; i < queue->len; ) {
HintSample *sample = &queue->samples[i];
if (!sample->own_data) {
- uint8_t* ptr = av_malloc(sample->size);
+ uint8_t *ptr = av_malloc(sample->size);
if (!ptr) {
/* Unable to allocate memory for this one, remove it */
memmove(queue->samples + i, queue->samples + i + 1,
* @param data buffer containing RTP packets
* @param size the size of the data buffer
* @param trk the MOVTrack for the hint track
- * @param pts pointer where the timestamp for the written RTP hint is stored
+ * @param dts pointer where the timestamp for the written RTP hint is stored
* @return the number of RTP packets in the written hint
*/
static int write_hint_packets(AVIOContext *out, const uint8_t *data,
- int size, MOVTrack *trk, int64_t *pts)
+ int size, MOVTrack *trk, int64_t *dts)
{
int64_t curpos;
int64_t count_pos, entries_pos;
uint32_t packet_len = AV_RB32(data);
uint16_t seq;
uint32_t ts;
+ int32_t ts_diff;
data += 4;
size -= 4;
if (packet_len > size || packet_len <= 12)
break;
- if (data[1] >= 200 && data[1] <= 204) {
+ if (RTP_PT_IS_RTCP(data[1])) {
/* RTCP packet, just skip */
data += packet_len;
size -= packet_len;
trk->max_packet_size = packet_len;
seq = AV_RB16(&data[2]);
- ts = AV_RB32(&data[4]);
+ ts = AV_RB32(&data[4]);
if (trk->prev_rtp_ts == 0)
trk->prev_rtp_ts = ts;
/* Unwrap the 32-bit RTP timestamp that wraps around often
* into a not (as often) wrapping 64-bit timestamp. */
- trk->cur_rtp_ts_unwrapped += (int32_t) (ts - trk->prev_rtp_ts);
- trk->prev_rtp_ts = ts;
- if (*pts == AV_NOPTS_VALUE)
- *pts = trk->cur_rtp_ts_unwrapped;
+ ts_diff = ts - trk->prev_rtp_ts;
+ if (ts_diff > 0) {
+ trk->cur_rtp_ts_unwrapped += ts_diff;
+ trk->prev_rtp_ts = ts;
+ ts_diff = 0;
+ }
+ if (*dts == AV_NOPTS_VALUE)
+ *dts = trk->cur_rtp_ts_unwrapped;
count++;
/* RTPpacket header */
avio_wb32(out, 0); /* relative_time */
avio_write(out, data, 2); /* RTP header */
avio_wb16(out, seq); /* RTPsequenceseed */
- avio_wb16(out, 0); /* reserved + flags */
+ avio_wb16(out, ts_diff ? 4 : 0); /* reserved + flags (extra_flag) */
entries_pos = avio_tell(out);
avio_wb16(out, 0); /* entry count */
+ if (ts_diff) { /* if extra_flag is set */
+ avio_wb32(out, 16); /* extra_information_length */
+ avio_wb32(out, 12); /* rtpoffsetTLV box */
+ avio_write(out, "rtpo", 4);
+ avio_wb32(out, ts_diff);
+ }
data += 12;
size -= 12;
}
int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
- int track_index, int sample)
+ int track_index, int sample,
+ uint8_t *sample_data, int sample_size)
{
MOVMuxContext *mov = s->priv_data;
MOVTrack *trk = &mov->tracks[track_index];
if (!rtp_ctx->pb)
return AVERROR(ENOMEM);
- sample_queue_push(&trk->sample_queue, pkt, sample);
+ if (sample_data)
+ sample_queue_push(&trk->sample_queue, sample_data, sample_size, sample);
+ else
+ sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample);
/* Feed the packet to the RTP muxer */
ff_write_chained(rtp_ctx, 0, pkt, s);
/* Fetch the output from the RTP muxer, open a new output buffer
* for next time. */
- size = url_close_dyn_buf(rtp_ctx->pb, &buf);
- if ((ret = url_open_dyn_packet_buf(&rtp_ctx->pb,
- RTP_MAX_PACKET_SIZE)) < 0)
+ size = avio_close_dyn_buf(rtp_ctx->pb, &buf);
+ if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb,
+ RTP_MAX_PACKET_SIZE)) < 0)
goto done;
if (size <= 0)
goto done;
/* Open a buffer for writing the hint */
- if ((ret = url_open_dyn_buf(&hintbuf)) < 0)
+ if ((ret = avio_open_dyn_buf(&hintbuf)) < 0)
goto done;
av_init_packet(&hint_pkt);
count = write_hint_packets(hintbuf, buf, size, trk, &hint_pkt.dts);
av_freep(&buf);
/* Write the hint data into the hint track */
- hint_pkt.size = size = url_close_dyn_buf(hintbuf, &buf);
+ hint_pkt.size = size = avio_close_dyn_buf(hintbuf, &buf);
hint_pkt.data = buf;
hint_pkt.pts = hint_pkt.dts;
hint_pkt.stream_index = track_index;
return ret;
}
-void ff_mov_close_hinting(MOVTrack *track) {
- AVFormatContext* rtp_ctx = track->rtp_ctx;
- uint8_t *ptr;
+void ff_mov_close_hinting(MOVTrack *track)
+{
+ AVFormatContext *rtp_ctx = track->rtp_ctx;
av_freep(&track->enc);
sample_queue_free(&track->sample_queue);
return;
if (rtp_ctx->pb) {
av_write_trailer(rtp_ctx);
- url_close_dyn_buf(rtp_ctx->pb, &ptr);
- av_free(ptr);
+ ffio_free_dyn_buf(&rtp_ctx->pb);
}
avformat_free_context(rtp_ctx);
}
-