[FFmpeg-devel] [PATCH] RTMP seek support
Howard Chu
hyc
Thu Apr 1 01:34:08 CEST 2010
Michael Niedermayer wrote:
> On Tue, Mar 30, 2010 at 06:42:50PM -0700, Howard Chu wrote:
>> Howard Chu wrote:
>>> Howard Chu wrote:
>>>> Howard Chu wrote:
>>>>> Howard Chu wrote:
>>>>>> This is a first stab at getting seek working on an RTMP stream.
>>
>>>>>> I've been testing with this stream:
>>>>>>
>>>>>> gdb --args ./ffplay_g
>>>>>> "rtmp://fms.scctv.net/annenberg//vod/world_of_chemistry_01
>>>>>> swfurl=http://www.learner.org/vod/swfs/player-licensed.swf
>>>>>> pageurl=http://www.learner.org/vod/vod_window.html?pid=793"
>>>>>
>>>>> Thanks to a tip from uau this is now working.
>>
>>> Note that the did_rseek flag wouldn't even be needed if the rest of flvdec
>>> always read from the start of a frame, instead of reading from the end of
>>> the
>>> previous frame, as it currently does. But I took a look at fixing that and
>>> the
>>> diff would be pretty large, so I chose this approach instead.
>>
>> It turned out to be not too bad to correct that, as this patch shows.
>>
>>> The patch for aviobuf.c is going to be needed regardless - you shouldn't
>>> be
>>> setting "s->pos = s->seek()" unconditionally, since s->seek may not be
>>> implemented. Storing a -32 in s->pos is bound to screw something else up.
>>
>> --
>> -- Howard Chu
>> CTO, Symas Corp. http://www.symas.com
>> Director, Highland Sun http://highlandsun.com/hyc/
>> Chief Architect, OpenLDAP http://www.openldap.org/project/
>
>> Index: libavformat/flvdec.c
>> ===================================================================
>> --- libavformat/flvdec.c (revision 22713)
>> +++ libavformat/flvdec.c (working copy)
>> @@ -270,6 +270,7 @@
>>
>> offset = get_be32(s->pb);
>> url_fseek(s->pb, offset, SEEK_SET);
>> + url_fskip(s->pb, 4);
>>
>> s->start_time = 0;
>>
>> @@ -295,9 +296,8 @@
>> int64_t dts, pts = AV_NOPTS_VALUE;
>> AVStream *st = NULL;
>>
>> - for(;;){
>> + do{
>> pos = url_ftell(s->pb);
>> - url_fskip(s->pb, 4); /* size of previous packet */
>> type = get_byte(s->pb);
>> size = get_be24(s->pb);
>> dts = get_be24(s->pb);
>> @@ -359,7 +359,7 @@
>> if ((flags& FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
>> av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
>> break;
>
>> - }
>> + } while(url_fskip(s->pb, 4),1);
>>
>
> putting the url_fskip() inside the loop at the end seems cleaner to me
Then the couple "continue"s inside the loop would need to be changed (e.g., to
"goto end_of_loop"). I usually opt for the patch that touches the least amount
of existing code and adds the least new code.
> also the url_fskip() movement could be a seperate patch
I guess you're right. At first it seemed to me that would also mean patching
the flv_read_seek functionality twice, but now I see it could have been split
out. I'll re-send as a separate patch.
> [...]
>> +static int flv_read_seek(AVFormatContext *s, int stream_index,
>> + int64_t ts, int flags)
>> +{
>> + int ret = AVERROR_NOTSUPP;
>> +
>> + if (url_is_streamed(s->pb))
>> + ret = av_url_read_fseek(s->pb, stream_index, ts, flags);
>> + return ret;
>> +}
>
> what if we get the flv from some other non seekable place like a pipe?
Then it will just return AVERROR_NOTSUPP, which is what av_url_read_fseek()
returns when ByteIOContext->read_seek is not implemented.
>> +
>> AVInputFormat flv_demuxer = {
>> "flv",
>> NULL_IF_CONFIG_SMALL("FLV format"),
>> @@ -449,6 +464,7 @@
>> flv_probe,
>> flv_read_header,
>> flv_read_packet,
>> + .read_seek = flv_read_seek,
>> .extensions = "flv",
>> .value = CODEC_ID_FLV1,
>> };
>> Index: libavformat/librtmp.c
>> ===================================================================
>> --- libavformat/librtmp.c (revision 22713)
>> +++ libavformat/librtmp.c (working copy)
>> @@ -127,7 +127,9 @@
>> return AVERROR_NOTSUPP;
>>
>> /* seeks are in milliseconds */
>> - timestamp = av_rescale(timestamp, AV_TIME_BASE, 1000);
>> + if (stream_index == -1)
>> + timestamp = av_rescale(timestamp, 1000, AV_TIME_BASE);
>> +
>> if (!RTMP_SendSeek(r, timestamp))
>> return -1;
>> return timestamp;
>
>> Index: libavformat/aviobuf.c
>> ===================================================================
>> --- libavformat/aviobuf.c (revision 22713)
>> +++ libavformat/aviobuf.c (working copy)
>> @@ -698,8 +698,11 @@
>> return AVERROR(ENOSYS);
>> ret = s->read_seek(h, stream_index, timestamp, flags);
>> if(ret>= 0) {
>> + int64_t pos;
>> s->buf_ptr = s->buf_end; // Flush buffer
>> - s->pos = s->seek(h, 0, SEEK_CUR);
>> + pos = s->seek(h, 0, SEEK_CUR);
>> + if (pos != AVERROR(ENOSYS))
>> + s->pos = pos;
>> }
>> return ret;
>> }
>
> shouldnt this return some kind of error if seek fails?
I don't know, you tell me. It obviously never checked for errors before. It
doesn't seem like this particular seek call can actually accomplish anything;
since it's referencing (0, SEEK_CUR) then if the underlying layers already
know where SEEK_CUR is, it's a no-op. And if the underlying layers don't know
where SEEK_CUR is, this isn't going to help them determine it.
And again, this should probably be a separate patch. Should I split it out?
--
-- Howard Chu
CTO, Symas Corp. http://www.symas.com
Director, Highland Sun http://highlandsun.com/hyc/
Chief Architect, OpenLDAP http://www.openldap.org/project/
More information about the ffmpeg-devel
mailing list