Commit cb7e2c1c authored by Kharkov Alexander's avatar Kharkov Alexander Committed by Anton Khirnov
Browse files

flvdec: read index stored in the 'keyframes' tag.



'keyframes' metatag is not part of the standard, it is just
convention to use such kind of metatag information for indexing.
Structure is following, it allows to have it inconsistent:
keyframes:
 times (array):
  time0 (num)
  time1 (num)
  time2 (num)
 filepositions (array)
  position0 (num)
  position1 (num)
Signed-off-by: default avatarAnton Khirnov <anton@khirnov.net>
parent 9dd94f83
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#include "avio_internal.h" #include "avio_internal.h"
#include "flv.h" #include "flv.h"
#define KEYFRAMES_TAG "keyframes"
#define KEYFRAMES_TIMESTAMP_TAG "times"
#define KEYFRAMES_BYTEOFFSET_TAG "filepositions"
typedef struct { typedef struct {
int wrong_dts; ///< wrong dts due to negative cts int wrong_dts; ///< wrong dts due to negative cts
} FLVContext; } FLVContext;
...@@ -125,6 +129,64 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) { ...@@ -125,6 +129,64 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) {
return length; return length;
} }
static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream *vstream, int64_t max_pos) {
unsigned int arraylen = 0, timeslen = 0, fileposlen = 0, i;
double num_val;
char str_val[256];
int64_t *times = NULL;
int64_t *filepositions = NULL;
int ret = 0;
while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
int64_t* current_array;
// Expect array object in context
if (avio_r8(ioc) != AMF_DATA_TYPE_ARRAY)
break;
arraylen = avio_rb32(ioc);
/*
* Expect only 'times' or 'filepositions' sub-arrays in other case refuse to use such metadata
* for indexing
*/
if (!strcmp(KEYFRAMES_TIMESTAMP_TAG, str_val) && !times) {
if (!(times = av_mallocz(sizeof(*times) * arraylen))) {
ret = AVERROR(ENOMEM);
goto finish;
}
timeslen = arraylen;
current_array = times;
} else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && !filepositions) {
if (!(filepositions = av_mallocz(sizeof(*filepositions) * arraylen))) {
ret = AVERROR(ENOMEM);
goto finish;
}
fileposlen = arraylen;
current_array = filepositions;
} else // unexpected metatag inside keyframes, will not use such metadata for indexing
break;
for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) {
if (avio_r8(ioc) != AMF_DATA_TYPE_NUMBER)
goto finish;
num_val = av_int2dbl(avio_rb64(ioc));
current_array[i] = num_val;
}
}
if (timeslen == fileposlen)
for(i = 0; i < arraylen; i++)
av_add_index_entry(vstream, filepositions[i], times[i]*1000, 0, 0, AVINDEX_KEYFRAME);
else
av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
finish:
av_freep(&times);
av_freep(&filepositions);
avio_seek(ioc, max_pos, SEEK_SET);
return ret;
}
static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) { static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) {
AVCodecContext *acodec, *vcodec; AVCodecContext *acodec, *vcodec;
AVIOContext *ioc; AVIOContext *ioc;
...@@ -149,6 +211,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst ...@@ -149,6 +211,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst
case AMF_DATA_TYPE_OBJECT: { case AMF_DATA_TYPE_OBJECT: {
unsigned int keylen; unsigned int keylen;
if (!strcmp(KEYFRAMES_TAG, key) && depth == 1)
if (parse_keyframes_index(s, ioc, vstream, max_pos) < 0)
return -1;
while(avio_tell(ioc) < max_pos - 2 && (keylen = avio_rb16(ioc))) { while(avio_tell(ioc) < max_pos - 2 && (keylen = avio_rb16(ioc))) {
avio_skip(ioc, keylen); //skip key string avio_skip(ioc, keylen); //skip key string
if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1) < 0) if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1) < 0)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment