Ejemplo n.º 1
0
static int flv_read_metabody(flv* p, format_reader* Reader, int64_t next_pos) 
{
    AMFDataType type;
    char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.

    //first object needs to be "onMetaData" string
	type = Reader->Read8(Reader);

    if(type != AMF_DATA_TYPE_STRING || amf_get_string(p,Reader, buffer, sizeof(buffer)) < 0 || tcscmp(buffer, "onMetaData"))
        return -1;

    //parse the second object (we want a mixed array)
    if(amf_parse_object(p,Reader, buffer, next_pos, 0) < 0)
        return -1;

    return 0;
}
Ejemplo n.º 2
0
static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) {
    AMFDataType type;
    AVStream *stream, *astream, *vstream, *dstream;
    AVIOContext *ioc;
    int i;
    char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.

    vstream = astream = dstream = NULL;
    ioc = s->pb;

    //first object needs to be "onMetaData" string
    type = avio_r8(ioc);
    if (type != AMF_DATA_TYPE_STRING ||
            amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
        return -1;

    if (!strcmp(buffer, "onTextData"))
        return 1;

    if (strcmp(buffer, "onMetaData"))
        return -1;

    //find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called.
    for(i = 0; i < s->nb_streams; i++) {
        stream = s->streams[i];
        if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = stream;
        else if(stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) astream = stream;
        else if(stream->codec->codec_type == AVMEDIA_TYPE_DATA) dstream = stream;
    }

    //parse the second object (we want a mixed array)
    if(amf_parse_object(s, astream, vstream, buffer, next_pos, 0) < 0)
        return -1;

    return 0;
}
Ejemplo n.º 3
0
static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) {
    AVCodecContext *acodec, *vcodec;
    AVIOContext *ioc;
    AMFDataType amf_type;
    char str_val[256];
    double num_val;

    num_val = 0;
    ioc = s->pb;

    amf_type = avio_r8(ioc);

    switch(amf_type) {
    case AMF_DATA_TYPE_NUMBER:
        num_val = av_int2double(avio_rb64(ioc));
        break;
    case AMF_DATA_TYPE_BOOL:
        num_val = avio_r8(ioc);
        break;
    case AMF_DATA_TYPE_STRING:
        if(amf_get_string(ioc, str_val, sizeof(str_val)) < 0)
            return -1;
        break;
    case AMF_DATA_TYPE_OBJECT:
        if ((vstream || astream) && ioc->seekable && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1)
            if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
                                      max_pos) < 0)
                av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");

        while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
            if (amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0)
                return -1; //if we couldn't skip, bomb out.
        }
        if(avio_r8(ioc) != AMF_END_OF_OBJECT)
            return -1;
        break;
    case AMF_DATA_TYPE_NULL:
    case AMF_DATA_TYPE_UNDEFINED:
    case AMF_DATA_TYPE_UNSUPPORTED:
        break; //these take up no additional space
    case AMF_DATA_TYPE_MIXEDARRAY:
        avio_skip(ioc, 4); //skip 32-bit max array index
        while(avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
            //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(avio_r8(ioc) != AMF_END_OF_OBJECT)
            return -1;
        break;
    case AMF_DATA_TYPE_ARRAY: {
        unsigned int arraylen, i;

        arraylen = avio_rb32(ioc);
        for(i = 0; i < arraylen && avio_tell(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.
        }
    }
    break;
    case AMF_DATA_TYPE_DATE:
        avio_skip(ioc, 8 + 2); //timestamp (double) and UTC offset (int16)
        break;
    default: //unsupported type, we couldn't skip
        return -1;
    }

    if(depth == 1 && key) { //only look for metadata values when we are not nested and key != NULL
        acodec = astream ? astream->codec : NULL;
        vcodec = vstream ? vstream->codec : NULL;

        if (amf_type == AMF_DATA_TYPE_NUMBER) {
            if (!strcmp(key, "duration"))
                s->duration = num_val * AV_TIME_BASE;
            else if (!strcmp(key, "videodatarate") && vcodec && 0 <= (int)(num_val * 1024.0))
                vcodec->bit_rate = num_val * 1024.0;
            else if (!strcmp(key, "audiodatarate") && acodec && 0 <= (int)(num_val * 1024.0))
                acodec->bit_rate = num_val * 1024.0;
            else if (!strcmp(key, "datastream")) {
                AVStream *st = create_stream(s, 2, AVMEDIA_TYPE_DATA);
                if (!st)
                    return AVERROR(ENOMEM);
                st->codec->codec_id = CODEC_ID_TEXT;
            }
        }

        if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
                ((!acodec && !strcmp(key, "audiocodecid")) ||
                 (!vcodec && !strcmp(key, "videocodecid"))))
            s->ctx_flags &= ~AVFMTCTX_NOHEADER; //If there is either audio/video missing, codecid will be an empty object

        if (!strcmp(key, "duration")        ||
                !strcmp(key, "filesize")        ||
                !strcmp(key, "width")           ||
                !strcmp(key, "height")          ||
                !strcmp(key, "videodatarate")   ||
                !strcmp(key, "framerate")       ||
                !strcmp(key, "videocodecid")    ||
                !strcmp(key, "audiodatarate")   ||
                !strcmp(key, "audiosamplerate") ||
                !strcmp(key, "audiosamplesize") ||
                !strcmp(key, "stereo")          ||
                !strcmp(key, "audiocodecid"))
            return 0;

        if(amf_type == AMF_DATA_TYPE_BOOL) {
            av_strlcpy(str_val, num_val > 0 ? "true" : "false", sizeof(str_val));
            av_dict_set(&s->metadata, key, str_val, 0);
        } else if(amf_type == AMF_DATA_TYPE_NUMBER) {
            snprintf(str_val, sizeof(str_val), "%.f", num_val);
            av_dict_set(&s->metadata, key, str_val, 0);
        } else if (amf_type == AMF_DATA_TYPE_STRING)
            av_dict_set(&s->metadata, key, str_val, 0);
    }

    return 0;
}
Ejemplo n.º 4
0
static int amf_parse_object(flv* p, format_reader* Reader, const char *key, int64_t max_pos, int depth) 
{
    AMFDataType amf_type;

    char str_val[256];

    conv c;

	double num_val;

    num_val = 0;

	amf_type = Reader->Read8(Reader);

    switch(amf_type) 
	{
        case AMF_DATA_TYPE_NUMBER:
			{
				c.src = Reader->ReadBE64(Reader);
				num_val =c.dst;
			}
			break;
        case AMF_DATA_TYPE_BOOL:
			num_val = Reader->Read8(Reader);
			break;
        case AMF_DATA_TYPE_STRING:
            if(amf_get_string(p,Reader, str_val, sizeof(str_val)) < 0)
                return -1;
            break;
        case AMF_DATA_TYPE_OBJECT: 
			{
				while(Reader->FilePos < max_pos - 2 && amf_get_string(p,Reader, str_val, sizeof(str_val)) > 0)
				{
					if(amf_parse_object(p,Reader, str_val, max_pos, depth + 1) < 0)
					{
						return -1; //if we couldn't skip, bomb out.
					}

				}
				if(Reader->Read8(Reader) != AMF_END_OF_OBJECT)
					return -1;
			}
            break;
        case AMF_DATA_TYPE_NULL:
        case AMF_DATA_TYPE_UNDEFINED:
        case AMF_DATA_TYPE_UNSUPPORTED:
            break; //these take up no additional space
        case AMF_DATA_TYPE_MIXEDARRAY:
			Reader->Skip(Reader,4); //skip 32-bit max array index
			while(Reader->FilePos < max_pos - 2 && amf_get_string(p,Reader, str_val, sizeof(str_val)) > 0) 
			{
                //this is the only case in which we would want a nested parse to not skip over the object
                if(amf_parse_object(p,Reader, str_val, max_pos, depth + 1) < 0)
                    return -1;
            }
			if(Reader->Read8(Reader) != AMF_END_OF_OBJECT)
				return -1;
            break;
        case AMF_DATA_TYPE_ARRAY: 
			{
				unsigned int arraylen, i;

				arraylen = Reader->ReadBE32(Reader);
				if(strcmp(key,"times")==0||strcmp(key,"filepositions")==0)
				{
					if(p->IndexNum == 0)
					{
						int32_t size;
						p->IndexNum  = arraylen;
						size = sizeof(flvindex)*p->IndexNum;
						size = ((size+SAFETAIL-1)/SAFETAIL)*SAFETAIL;
						if (!AllocBlock(size,&p->IndexBuffer,0,HEAP_ANY))
							return ERR_OUT_OF_MEMORY;
					}
				}

				p->IndexCur  = 0;

				for(i = 0; i < arraylen && Reader->FilePos < max_pos - 1; i++) 
				{
					if(amf_parse_object(p,Reader,  key, max_pos, depth + 1) < 0)
						return -1; //if we couldn't skip, bomb out.
				}
        }
            break;
        case AMF_DATA_TYPE_DATE:
			Reader->Skip(Reader, 8 + 2); //timestamp (double) and UTC offset (int16)
            break;
        default: //unsupported type, we couldn't skip
            return -1;
    }

    if(depth == 1 &&key) 
	{	//only look for metadata values when we are not nested and key != NULL
        if(amf_type == AMF_DATA_TYPE_BOOL) 
		{
        } 
		else if(amf_type == AMF_DATA_TYPE_NUMBER) 
		{
            if(!tcscmp(key, "duration")) 
				p->Format.Duration = Scale(num_val, TICKSPERSEC, 1);
        } 
		else if (amf_type == AMF_DATA_TYPE_STRING)
		{
			
		}
		else if(amf_type == AMF_DATA_TYPE_DATE)
		{

		}
    }
	else if(key)
	{
		if(tcscmp(key,"times")==0)
		{
			((flvindex*)IndexBuffer(p,p->IndexCur))->times = num_val;
			p->IndexCur++;
		}
		else if(tcscmp(key,"filepositions")==0)
		{
			((flvindex*)IndexBuffer(p,p->IndexCur))->pos = num_val;
			p->IndexCur++;
		}
	}

    return 0;
}