[FFmpeg-devel] [PATCH] support for flvtool2 "keyframes based" generated index in FLV format decoder
Vladimir Pantelic
vladoman
Mon Jan 24 12:42:54 CET 2011
Kharkov Alexander wrote:
> New patch attached, after processing comments.
> Changes:
> * structures, types, constants renamed to not mention flvtool2
> * use av_mallocz for allocation to avoid unnecessary initialization
> * free metadata index data when it is no longer required
>
> On 21 January 2011 07:34, Kharkov Alexander<kharkovalexander at gmail.com> wrote:
>> Thanks for review, agree with all your points, will fix and resent.
>> Details:
>> * "keyframes" metatag does not stated in FLV specs but often
>> recommeded, I found at least one more free tool which inject it FLVMDI
>> * index data really can be free right after it is passed to av_add_index_entry
>> * code spread all over just because I want to touch exsting metadata
>> parser behavior minmal (all this recursion, loops, etc.) that is why I
>> did not create separate function which simply parse keyframes object
Could you rewrite the patch to read all the index stuff in one single
function, that should allow you to drop a lot of your temporary
variables and flags and will also make it much easier to understand.
> flvdec.c.diff
>
>
> Index: libavformat/flvdec.c
> ===================================================================
> --- libavformat/flvdec.c (revision 26327)
> +++ libavformat/flvdec.c (working copy)
> @@ -30,8 +30,34 @@
> #include "avformat.h"
> #include "flv.h"
>
> +#define METADATA_KEYFRAMES_TAG "keyframes"
> +#define METADATA_KEYFRAMES_TIMESTAMP_TAG "times"
> +#define METADATA_KEYFRAMES_BYTEOFFSET_TAG "filepositions"
> +
> typedef struct {
> + int64_t byte_offset;
> + int64_t time_offset;
> +} MedatadataKeyframeIndex;
> +
> +typedef struct {
> + int keyframes_object_parse;
> +
> + int filepositions_array_parse;
> + int fill_filepositions;
> + int num_filepositions_processed;
> +
> + int times_array_parse;
> + int fill_timestamps;
> + int num_timestamps_processed;
> +
> + int num_indexed_keyframes;
> +
> + MedatadataKeyframeIndex *keyframe_index;
> +} MetadataKeyframesIndex;
> +
> +typedef struct {
> int wrong_dts; ///< wrong dts due to negative cts
> + MetadataKeyframesIndex *metadata_keyframes_index;
> } FLVContext;
>
> static int flv_probe(AVProbeData *p)
> @@ -130,6 +156,8 @@
> AMFDataType amf_type;
> char str_val[256];
> double num_val;
> + unsigned int index_iter;
> + FLVContext *flv = s->priv_data;
>
> num_val = 0;
> ioc = s->pb;
> @@ -138,7 +166,16 @@
>
> switch(amf_type) {
> case AMF_DATA_TYPE_NUMBER:
> - num_val = av_int2dbl(get_be64(ioc)); break;
> + num_val = av_int2dbl(get_be64(ioc));
> + if (flv->metadata_keyframes_index->times_array_parse&& depth == 3&&
> + flv->metadata_keyframes_index->num_timestamps_processed< flv->metadata_keyframes_index->num_indexed_keyframes) {
> + flv->metadata_keyframes_index->keyframe_index[flv->metadata_keyframes_index->num_timestamps_processed++].time_offset = num_val;
> + }
> + if (flv->metadata_keyframes_index->filepositions_array_parse&& depth == 3
> +&& flv->metadata_keyframes_index->num_filepositions_processed< flv->metadata_keyframes_index->num_indexed_keyframes) {
> + flv->metadata_keyframes_index->keyframe_index[flv->metadata_keyframes_index->num_filepositions_processed++].byte_offset = num_val;
> + }
> + break;
as said
> case AMF_DATA_TYPE_BOOL:
> num_val = get_byte(ioc); break;
> case AMF_DATA_TYPE_STRING:
> @@ -149,9 +186,21 @@
> unsigned int keylen;
>
> while(url_ftell(ioc)< max_pos - 2&& (keylen = get_be16(ioc))) {
> - url_fskip(ioc, keylen); //skip key string
> + get_buffer(ioc, str_val, keylen);
> + str_val[keylen] = '\0';
> + if (flv->metadata_keyframes_index->keyframes_object_parse&& !strcmp(METADATA_KEYFRAMES_TIMESTAMP_TAG, str_val)&& depth == 1) {
> + flv->metadata_keyframes_index->times_array_parse = 1;
> + }
> + if (flv->metadata_keyframes_index->keyframes_object_parse&& !strcmp(METADATA_KEYFRAMES_BYTEOFFSET_TAG, str_val)&& depth == 1) {
> + flv->metadata_keyframes_index->filepositions_array_parse = 1;
> + }
> +
> + //url_fskip(ioc, keylen); //skip key string
> if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1)< 0)
> return -1; //if we couldn't skip, bomb out.
> +
> + flv->metadata_keyframes_index->times_array_parse = 0;
> + flv->metadata_keyframes_index->filepositions_array_parse = 0;
this index reading
> }
> if(get_byte(ioc) != AMF_END_OF_OBJECT)
> return -1;
> @@ -164,10 +213,25 @@
> case AMF_DATA_TYPE_MIXEDARRAY:
> url_fskip(ioc, 4); //skip 32-bit max array index
> while(url_ftell(ioc)< max_pos - 2&& amf_get_string(ioc, str_val, sizeof(str_val))> 0) {
> + if (!strcmp(METADATA_KEYFRAMES_TAG, str_val)&& depth == 0) {
> + flv->metadata_keyframes_index->keyframes_object_parse = 1;
> + }
is in
> //this is the only case in which we would want a nested parse to not skip over the object
> if(amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1)< 0)
> return -1;
> - }
> +
> + if (flv->metadata_keyframes_index->keyframes_object_parse&& depth == 0) {
> + // we fnish 'keyframes' metadata tag parsing, modify AV index based on this data
> + for (index_iter = 0; index_iter< flv->metadata_keyframes_index->num_indexed_keyframes; ++index_iter) {
> + int64_t ts = flv->metadata_keyframes_index->keyframe_index[index_iter].time_offset;
> + int64_t byte_offset = flv->metadata_keyframes_index->keyframe_index[index_iter].byte_offset;
> + av_add_index_entry(vstream, byte_offset, ts*1000, 0, 0, AVINDEX_KEYFRAME);
> + }
> + // cleanup
> + av_freep(&flv->metadata_keyframes_index->keyframe_index);
> + }
> + flv->metadata_keyframes_index->keyframes_object_parse = 0;
> + }
too many
> if(get_byte(ioc) != AMF_END_OF_OBJECT)
> return -1;
> break;
> @@ -175,10 +239,28 @@
> unsigned int arraylen, i;
>
> arraylen = get_be32(ioc);
> + if (flv->metadata_keyframes_index->filepositions_array_parse&& depth == 2) {
> + // allocate array to keep keyframe_index
> + if (flv->metadata_keyframes_index->keyframe_index == 0) {
> + flv->metadata_keyframes_index->keyframe_index = av_malloc(sizeof(MedatadataKeyframeIndex) * arraylen);
> + flv->metadata_keyframes_index->num_indexed_keyframes = arraylen;
> + }
> + flv->metadata_keyframes_index->fill_filepositions = 1;
> + }
> + if (flv->metadata_keyframes_index->times_array_parse&& depth == 2) {
> + // allocate array to keep keyframe_index
> + if (flv->metadata_keyframes_index->keyframe_index == 0) {
> + flv->metadata_keyframes_index->keyframe_index = av_malloc(sizeof(MedatadataKeyframeIndex) * arraylen);
> + flv->metadata_keyframes_index->num_indexed_keyframes = arraylen;
> + }
> + flv->metadata_keyframes_index->fill_timestamps = 1;
> + }
> for(i = 0; i< arraylen&& url_ftell(ioc)< max_pos - 1; i++) {
> if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1)< 0)
> return -1; //if we couldn't skip, bomb out.
> }
> + flv->metadata_keyframes_index->fill_filepositions = 0;
> + flv->metadata_keyframes_index->fill_timestamps = 0;
> }
places
> break;
> case AMF_DATA_TYPE_DATE:
> @@ -214,8 +296,10 @@
> AMFDataType type;
> AVStream *stream, *astream, *vstream;
> ByteIOContext *ioc;
> +
> int i;
> char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.
> + FLVContext *flv = s->priv_data;
>
> astream = NULL;
> vstream = NULL;
> @@ -233,10 +317,17 @@
> else if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = stream;
> }
>
> +
> + // allocate "keyframes" based index
> + flv->metadata_keyframes_index = av_mallocz(sizeof(MetadataKeyframesIndex) * 1);
> +
> //parse the second object (we want a mixed array)
> if(amf_parse_object(s, astream, vstream, buffer, next_pos, 0)< 0)
> return -1;
>
> + // cleanup "keyframes" based index
> + av_freep(&flv->metadata_keyframes_index);
> +
> return 0;
> }
>
>
>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at mplayerhq.hu
> https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list