aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2012-02-28 03:38:58 +0100
committerMichael Niedermayer <michaelni@gmx.at>2012-02-28 03:38:58 +0100
commite3822886ebb3ae97bdae9be264d891f1d35c960b (patch)
tree0debfb9843f9a8b56454a1bbe9b679827e9c2615 /libavformat
parentf1808e304834304122ebce9325eb997a673a9dc2 (diff)
parentd10319d87f7f408dc69e1540498e87e2860e945d (diff)
downloadffmpeg-e3822886ebb3ae97bdae9be264d891f1d35c960b.tar.gz
Merge remote-tracking branch 'qatar/master'
* qatar/master: avcodec_default_reget_buffer(): fix compilation in DEBUG mode fate: Overhaul WavPack coverage h264: fix mmxext chroma deblock to use correct TC values. flvdec: Remove the now redundant check for known broken metadata creator flvdec: Validate index entries added from metadata while reading rtsp: Handle requests from server to client movenc: use timestamps instead of frame_size for samples-per-packet movenc: use the first cluster duration as the tfhd default duration movenc: factorize calculation of cluster duration into a separate function doc/APIchanges: fill in missing dates and hashes. lavc: reorder AVCodecContext fields. lavc: reorder AVFrame fields. Conflicts: doc/APIchanges libavcodec/avcodec.h libavformat/flvdec.c libavformat/movenc.c tests/fate/lossless-audio.mak Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/flvdec.c60
-rw-r--r--libavformat/movenc.c54
-rw-r--r--libavformat/rtsp.c58
3 files changed, 144 insertions, 28 deletions
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index bbc71636f1..8ae79501b4 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -35,12 +35,20 @@
#include "avio_internal.h"
#include "flv.h"
+#define VALIDATE_INDEX_TS_THRESH 2500
+
typedef struct {
int wrong_dts; ///< wrong dts due to negative cts
uint8_t *new_extradata[FLV_STREAM_TYPE_NB];
int new_extradata_size[FLV_STREAM_TYPE_NB];
int last_sample_rate;
int last_channels;
+ struct {
+ int64_t dts;
+ int64_t pos;
+ } validate_index[2];
+ int validate_next;
+ int validate_count;
} FLVContext;
static int flv_probe(AVProbeData *p)
@@ -137,6 +145,7 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) {
}
static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream *vstream, int64_t max_pos) {
+ FLVContext *flv = s->priv_data;
unsigned int timeslen = 0, fileposlen = 0, i;
char str_val[256];
int64_t *times = NULL;
@@ -192,18 +201,15 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
}
if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) {
- int64_t av_unused dts, size0, size1;
- avio_seek(ioc, filepositions[1]-4, SEEK_SET);
- size0 = avio_rb32(ioc);
- avio_r8(ioc);
- size1 = avio_rb24(ioc);
- dts = avio_rb24(ioc);
- dts |= avio_r8(ioc) << 24;
- if (size0 > filepositions[1] || FFABS(dts - times[1]*1000)>5000/*arbitraray threshold to detect invalid index*/)
- goto invalid;
- for(i = 0; i < timeslen; i++)
+ for (i = 0; i < fileposlen; i++) {
av_add_index_entry(vstream, filepositions[i], times[i]*1000,
0, 0, AVINDEX_KEYFRAME);
+ if (i < 2) {
+ flv->validate_index[i].pos = filepositions[i];
+ flv->validate_index[i].dts = times[i] * 1000;
+ flv->validate_count = i + 1;
+ }
+ }
} else {
invalid:
av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
@@ -444,6 +450,22 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream,
return 0;
}
+static void clear_index_entries(AVFormatContext *s, int64_t pos)
+{
+ int i, j, out;
+ av_log(s, AV_LOG_WARNING, "Found invalid index entries, clearing the index.\n");
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ /* Remove all index entries that point to >= pos */
+ out = 0;
+ for (j = 0; j < st->nb_index_entries; j++) {
+ if (st->index_entries[j].pos < pos)
+ st->index_entries[out++] = st->index_entries[j];
+ }
+ st->nb_index_entries = out;
+ }
+}
+
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
@@ -467,6 +489,22 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
avio_skip(s->pb, 3); /* stream id, always 0 */
flags = 0;
+ if (flv->validate_next < flv->validate_count) {
+ int64_t validate_pos = flv->validate_index[flv->validate_next].pos;
+ if (pos == validate_pos) {
+ if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <=
+ VALIDATE_INDEX_TS_THRESH) {
+ flv->validate_next++;
+ } else {
+ clear_index_entries(s, validate_pos);
+ flv->validate_count = 0;
+ }
+ } else if (pos > validate_pos) {
+ clear_index_entries(s, validate_pos);
+ flv->validate_count = 0;
+ }
+ }
+
if(size == 0)
continue;
@@ -654,6 +692,8 @@ leave:
static int flv_read_seek(AVFormatContext *s, int stream_index,
int64_t ts, int flags)
{
+ FLVContext *flv = s->priv_data;
+ flv->validate_count = 0;
return avio_seek_time(s->pb, stream_index, ts, flags);
}
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 472281957b..7f970be35f 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -565,6 +565,42 @@ static int mov_get_lpcm_flags(enum CodecID codec_id)
}
}
+static int get_cluster_duration(MOVTrack *track, int cluster_idx)
+{
+ int64_t next_dts;
+
+ if (cluster_idx >= track->entry)
+ return 0;
+
+ if (cluster_idx + 1 == track->entry)
+ next_dts = track->track_duration + track->start_dts;
+ else
+ next_dts = track->cluster[cluster_idx + 1].dts;
+
+ return next_dts - track->cluster[cluster_idx].dts;
+}
+
+static int get_samples_per_packet(MOVTrack *track)
+{
+ int i, first_duration;
+
+// return track->enc->frame_size;
+
+ /* use 1 for raw PCM */
+ if (!track->audio_vbr)
+ return 1;
+
+ /* check to see if duration is constant for all clusters */
+ if (!track->entry)
+ return 0;
+ first_duration = get_cluster_duration(track, 0);
+ for (i = 1; i < track->entry; i++) {
+ if (get_cluster_duration(track, i) != first_duration)
+ return 0;
+ }
+ return first_duration;
+}
+
static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
@@ -607,7 +643,7 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, av_get_bits_per_sample(track->enc->codec_id));
avio_wb32(pb, mov_get_lpcm_flags(track->enc->codec_id));
avio_wb32(pb, track->sample_size);
- avio_wb32(pb, track->enc->frame_size);
+ avio_wb32(pb, get_samples_per_packet(track));
} else {
if (track->mode == MODE_MOV) {
avio_wb16(pb, track->enc->channels);
@@ -1143,9 +1179,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
av_malloc(track->entry * sizeof(*stts_entries)) : /* worst case */
NULL;
for (i=0; i<track->entry; i++) {
- int64_t duration = i + 1 == track->entry ?
- track->track_duration - track->cluster[i].dts + track->start_dts : /* readjusting */
- track->cluster[i+1].dts - track->cluster[i].dts;
+ int duration = get_cluster_duration(track, i);
if (i && duration == stts_entries[entries].duration) {
stts_entries[entries].count++; /* compress */
} else {
@@ -2262,7 +2296,7 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track,
if (flags & MOV_TFHD_BASE_DATA_OFFSET)
avio_wb64(pb, moof_offset);
if (flags & MOV_TFHD_DEFAULT_DURATION) {
- track->default_duration = track->audio_vbr ? track->enc->frame_size : 1;
+ track->default_duration = get_cluster_duration(track, 0);
avio_wb32(pb, track->default_duration);
}
if (flags & MOV_TFHD_DEFAULT_SIZE) {
@@ -2295,10 +2329,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
int i;
for (i = 0; i < track->entry; i++) {
- int64_t duration = i + 1 == track->entry ?
- track->track_duration - track->cluster[i].dts + track->start_dts :
- track->cluster[i + 1].dts - track->cluster[i].dts;
- if (duration != track->default_duration)
+ if (get_cluster_duration(track, i) != track->default_duration)
flags |= MOV_TRUN_SAMPLE_DURATION;
if (track->cluster[i].size != track->default_size)
flags |= MOV_TRUN_SAMPLE_SIZE;
@@ -2322,11 +2353,8 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, get_sample_flags(track, &track->cluster[0]));
for (i = 0; i < track->entry; i++) {
- int64_t duration = i + 1 == track->entry ?
- track->track_duration - track->cluster[i].dts + track->start_dts :
- track->cluster[i + 1].dts - track->cluster[i].dts;
if (flags & MOV_TRUN_SAMPLE_DURATION)
- avio_wb32(pb, duration);
+ avio_wb32(pb, get_cluster_duration(track, i));
if (flags & MOV_TRUN_SAMPLE_SIZE)
avio_wb32(pb, track->cluster[i].size);
if (flags & MOV_TRUN_SAMPLE_FLAGS)
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 0d919ae874..023411c9f5 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -900,9 +900,13 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
char buf[4096], buf1[1024], *q;
unsigned char ch;
const char *p;
- int ret, content_length, line_count = 0;
+ int ret, content_length, line_count = 0, request = 0;
unsigned char *content = NULL;
+start:
+ line_count = 0;
+ request = 0;
+ content = NULL;
memset(reply, 0, sizeof(*reply));
/* parse reply (XXX: use buffers) */
@@ -938,9 +942,15 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
if (line_count == 0) {
/* get reply code */
get_word(buf1, sizeof(buf1), &p);
- get_word(buf1, sizeof(buf1), &p);
- reply->status_code = atoi(buf1);
- av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ if (!strncmp(buf1, "RTSP/", 5)) {
+ get_word(buf1, sizeof(buf1), &p);
+ reply->status_code = atoi(buf1);
+ av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ } else {
+ av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method
+ get_word(buf1, sizeof(buf1), &p); // object
+ request = 1;
+ }
} else {
ff_rtsp_parse_line(reply, p, rt, method);
av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
@@ -949,7 +959,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
line_count++;
}
- if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
+ if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0' && !request)
av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
content_length = reply->content_length;
@@ -964,6 +974,44 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
else
av_free(content);
+ if (request) {
+ char buf[1024];
+ char base64buf[AV_BASE64_SIZE(sizeof(buf))];
+ const char* ptr = buf;
+
+ if (!strcmp(reply->reason, "OPTIONS")) {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 200 OK\r\n");
+ if (reply->seq)
+ av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", reply->seq);
+ if (reply->session_id[0])
+ av_strlcatf(buf, sizeof(buf), "Session: %s\r\n",
+ reply->session_id);
+ } else {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 501 Not Implemented\r\n");
+ }
+ av_strlcat(buf, "\r\n", sizeof(buf));
+
+ if (rt->control_transport == RTSP_MODE_TUNNEL) {
+ av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+ ptr = base64buf;
+ }
+ ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr));
+
+ rt->last_cmd_time = av_gettime();
+ /* Even if the request from the server had data, it is not the data
+ * that the caller wants or expects. The memory could also be leaked
+ * if the actual following reply has content data. */
+ if (content_ptr)
+ av_freep(content_ptr);
+ /* If method is set, this is called from ff_rtsp_send_cmd,
+ * where a reply to exactly this request is awaited. For
+ * callers from within packet reciving, we just want to
+ * return to the caller and go back to receiving packets. */
+ if (method)
+ goto start;
+ return 0;
+ }
+
if (rt->seq != reply->seq) {
av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
rt->seq, reply->seq);