* 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>tags/n0.11
| @@ -35,19 +35,19 @@ API changes, most recent first: | |||||
| 2012-01-24 - xxxxxxx - lavfi 2.60.100 | 2012-01-24 - xxxxxxx - lavfi 2.60.100 | ||||
| Add avfilter_graph_dump. | Add avfilter_graph_dump. | ||||
| 2012-xx-xx - xxxxxxx - lavu 51.24.0 - error.h | |||||
| 2012-02-25 - c9bca80 - lavu 51.24.0 - error.h | |||||
| Add AVERROR_UNKNOWN | Add AVERROR_UNKNOWN | ||||
| 2012-xx-xx - xxxxxxx - lavc 54.x.x | |||||
| 2012-02-20 - e9cda85 - lavc 54.2.0 | |||||
| Add duration field to AVCodecParserContext | Add duration field to AVCodecParserContext | ||||
| 2012-02-xx - xxxxxxx - lavu 51.23.1 - mathematics.h | |||||
| 2012-02-20 - 0b42a93 - lavu 51.23.1 - mathematics.h | |||||
| Add av_rescale_q_rnd() | Add av_rescale_q_rnd() | ||||
| 2012-02-xx - xxxxxxx - lavu 51.22.1 - pixdesc.h | |||||
| 2012-02-08 - 38d5533 - lavu 51.22.1 - pixdesc.h | |||||
| Add PIX_FMT_PSEUDOPAL flag. | Add PIX_FMT_PSEUDOPAL flag. | ||||
| 2012-02-01 - xxxxxxx - lavc 54.01.0 | |||||
| 2012-02-08 - 52f82a1 - lavc 54.01.0 | |||||
| Add avcodec_encode_video2() and deprecate avcodec_encode_video(). | Add avcodec_encode_video2() and deprecate avcodec_encode_video(). | ||||
| 2012-02-01 - 316fc74 - lavc 54.01.0 | 2012-02-01 - 316fc74 - lavc 54.01.0 | ||||
| @@ -480,7 +480,7 @@ static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src) | |||||
| dst->slice_flags = src->slice_flags; | dst->slice_flags = src->slice_flags; | ||||
| dst->flags2 = src->flags2; | dst->flags2 = src->flags2; | ||||
| copy_fields(skip_loop_filter, bidir_refine); | |||||
| copy_fields(skip_loop_filter, subtitle_header); | |||||
| dst->frame_number = src->frame_number; | dst->frame_number = src->frame_number; | ||||
| dst->reordered_opaque = src->reordered_opaque; | dst->reordered_opaque = src->reordered_opaque; | ||||
| @@ -603,7 +603,7 @@ int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic){ | |||||
| return s->get_buffer(s, pic); | return s->get_buffer(s, pic); | ||||
| } | } | ||||
| assert(s->pix_fmt == pic->pix_fmt); | |||||
| assert(s->pix_fmt == pic->format); | |||||
| /* If internal buffer type return the same buffer */ | /* If internal buffer type return the same buffer */ | ||||
| if(pic->type == FF_BUFFER_TYPE_INTERNAL) { | if(pic->type == FF_BUFFER_TYPE_INTERNAL) { | ||||
| @@ -876,7 +876,7 @@ cglobal deblock_v_chroma_10_%1, 5,7-(mmsize/16),8*(mmsize/16) | |||||
| %if mmsize < 16 | %if mmsize < 16 | ||||
| add r0, mmsize | add r0, mmsize | ||||
| add r5, mmsize | add r5, mmsize | ||||
| add r4, mmsize/8 | |||||
| add r4, mmsize/4 | |||||
| dec r6 | dec r6 | ||||
| jg .loop | jg .loop | ||||
| REP_RET | REP_RET | ||||
| @@ -35,12 +35,20 @@ | |||||
| #include "avio_internal.h" | #include "avio_internal.h" | ||||
| #include "flv.h" | #include "flv.h" | ||||
| #define VALIDATE_INDEX_TS_THRESH 2500 | |||||
| typedef struct { | typedef struct { | ||||
| int wrong_dts; ///< wrong dts due to negative cts | int wrong_dts; ///< wrong dts due to negative cts | ||||
| uint8_t *new_extradata[FLV_STREAM_TYPE_NB]; | uint8_t *new_extradata[FLV_STREAM_TYPE_NB]; | ||||
| int new_extradata_size[FLV_STREAM_TYPE_NB]; | int new_extradata_size[FLV_STREAM_TYPE_NB]; | ||||
| int last_sample_rate; | int last_sample_rate; | ||||
| int last_channels; | int last_channels; | ||||
| struct { | |||||
| int64_t dts; | |||||
| int64_t pos; | |||||
| } validate_index[2]; | |||||
| int validate_next; | |||||
| int validate_count; | |||||
| } FLVContext; | } FLVContext; | ||||
| static int flv_probe(AVProbeData *p) | 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) { | 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; | unsigned int timeslen = 0, fileposlen = 0, i; | ||||
| char str_val[256]; | char str_val[256]; | ||||
| int64_t *times = NULL; | 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]) { | 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, | av_add_index_entry(vstream, filepositions[i], times[i]*1000, | ||||
| 0, 0, AVINDEX_KEYFRAME); | 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 { | } else { | ||||
| invalid: | invalid: | ||||
| av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n"); | 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; | 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) | static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) | ||||
| { | { | ||||
| FLVContext *flv = s->priv_data; | 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 */ | avio_skip(s->pb, 3); /* stream id, always 0 */ | ||||
| flags = 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) | if(size == 0) | ||||
| continue; | continue; | ||||
| @@ -654,6 +692,8 @@ leave: | |||||
| static int flv_read_seek(AVFormatContext *s, int stream_index, | static int flv_read_seek(AVFormatContext *s, int stream_index, | ||||
| int64_t ts, int flags) | int64_t ts, int flags) | ||||
| { | { | ||||
| FLVContext *flv = s->priv_data; | |||||
| flv->validate_count = 0; | |||||
| return avio_seek_time(s->pb, stream_index, ts, flags); | return avio_seek_time(s->pb, stream_index, ts, flags); | ||||
| } | } | ||||
| @@ -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) | static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) | ||||
| { | { | ||||
| int64_t pos = avio_tell(pb); | 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, av_get_bits_per_sample(track->enc->codec_id)); | ||||
| avio_wb32(pb, mov_get_lpcm_flags(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->sample_size); | ||||
| avio_wb32(pb, track->enc->frame_size); | |||||
| avio_wb32(pb, get_samples_per_packet(track)); | |||||
| } else { | } else { | ||||
| if (track->mode == MODE_MOV) { | if (track->mode == MODE_MOV) { | ||||
| avio_wb16(pb, track->enc->channels); | 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 */ | av_malloc(track->entry * sizeof(*stts_entries)) : /* worst case */ | ||||
| NULL; | NULL; | ||||
| for (i=0; i<track->entry; 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 : /* readjusting */ | |||||
| track->cluster[i+1].dts - track->cluster[i].dts; | |||||
| int duration = get_cluster_duration(track, i); | |||||
| if (i && duration == stts_entries[entries].duration) { | if (i && duration == stts_entries[entries].duration) { | ||||
| stts_entries[entries].count++; /* compress */ | stts_entries[entries].count++; /* compress */ | ||||
| } else { | } else { | ||||
| @@ -2262,7 +2296,7 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track, | |||||
| if (flags & MOV_TFHD_BASE_DATA_OFFSET) | if (flags & MOV_TFHD_BASE_DATA_OFFSET) | ||||
| avio_wb64(pb, moof_offset); | avio_wb64(pb, moof_offset); | ||||
| if (flags & MOV_TFHD_DEFAULT_DURATION) { | 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); | avio_wb32(pb, track->default_duration); | ||||
| } | } | ||||
| if (flags & MOV_TFHD_DEFAULT_SIZE) { | if (flags & MOV_TFHD_DEFAULT_SIZE) { | ||||
| @@ -2295,10 +2329,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track) | |||||
| int i; | int i; | ||||
| for (i = 0; i < track->entry; 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; | flags |= MOV_TRUN_SAMPLE_DURATION; | ||||
| if (track->cluster[i].size != track->default_size) | if (track->cluster[i].size != track->default_size) | ||||
| flags |= MOV_TRUN_SAMPLE_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])); | avio_wb32(pb, get_sample_flags(track, &track->cluster[0])); | ||||
| for (i = 0; i < track->entry; 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 (flags & MOV_TRUN_SAMPLE_DURATION) | if (flags & MOV_TRUN_SAMPLE_DURATION) | ||||
| avio_wb32(pb, duration); | |||||
| avio_wb32(pb, get_cluster_duration(track, i)); | |||||
| if (flags & MOV_TRUN_SAMPLE_SIZE) | if (flags & MOV_TRUN_SAMPLE_SIZE) | ||||
| avio_wb32(pb, track->cluster[i].size); | avio_wb32(pb, track->cluster[i].size); | ||||
| if (flags & MOV_TRUN_SAMPLE_FLAGS) | if (flags & MOV_TRUN_SAMPLE_FLAGS) | ||||
| @@ -900,9 +900,13 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, | |||||
| char buf[4096], buf1[1024], *q; | char buf[4096], buf1[1024], *q; | ||||
| unsigned char ch; | unsigned char ch; | ||||
| const char *p; | const char *p; | ||||
| int ret, content_length, line_count = 0; | |||||
| int ret, content_length, line_count = 0, request = 0; | |||||
| unsigned char *content = NULL; | unsigned char *content = NULL; | ||||
| start: | |||||
| line_count = 0; | |||||
| request = 0; | |||||
| content = NULL; | |||||
| memset(reply, 0, sizeof(*reply)); | memset(reply, 0, sizeof(*reply)); | ||||
| /* parse reply (XXX: use buffers) */ | /* parse reply (XXX: use buffers) */ | ||||
| @@ -938,9 +942,15 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, | |||||
| if (line_count == 0) { | if (line_count == 0) { | ||||
| /* get reply code */ | /* get reply code */ | ||||
| get_word(buf1, sizeof(buf1), &p); | 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 { | } else { | ||||
| ff_rtsp_parse_line(reply, p, rt, method); | ff_rtsp_parse_line(reply, p, rt, method); | ||||
| av_strlcat(rt->last_reply, p, sizeof(rt->last_reply)); | 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++; | 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)); | av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); | ||||
| content_length = reply->content_length; | content_length = reply->content_length; | ||||
| @@ -964,6 +974,44 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, | |||||
| else | else | ||||
| av_free(content); | 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) { | if (rt->seq != reply->seq) { | ||||
| av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n", | av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n", | ||||
| rt->seq, reply->seq); | rt->seq, reply->seq); | ||||
| @@ -15,3 +15,4 @@ fate-lossless-tta: CMD = crc -i $(SAMPLES)/lossless-audio/inside.tta | |||||
| FATE_TESTS += $(FATE_LOSSLESS_AUDIO) | FATE_TESTS += $(FATE_LOSSLESS_AUDIO) | ||||
| fate-lossless-audio: $(FATE_LOSSLESS_AUDIO) | fate-lossless-audio: $(FATE_LOSSLESS_AUDIO) | ||||