diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-02-28 03:38:58 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-02-28 03:38:58 +0100 |
commit | e3822886ebb3ae97bdae9be264d891f1d35c960b (patch) | |
tree | 0debfb9843f9a8b56454a1bbe9b679827e9c2615 /libavformat | |
parent | f1808e304834304122ebce9325eb997a673a9dc2 (diff) | |
parent | d10319d87f7f408dc69e1540498e87e2860e945d (diff) | |
download | ffmpeg-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.c | 60 | ||||
-rw-r--r-- | libavformat/movenc.c | 54 | ||||
-rw-r--r-- | libavformat/rtsp.c | 58 |
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); |