⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flvdecoder.cpp

📁 symbian下的FLV播放视频源码 可以快速便捷的播放FLV格式的视频
💻 CPP
字号:
#include <sys/stat.h>
#include "FLVDecoder.h"

TFLVGlobalVar flvGlobalVar;

int filesize(CNeoFILE* aNeoFile)
{	
	return aNeoFile->FSize();
}

int filesize_from_current(CNeoFILE* aNeoFile)
{
	return filesize(aNeoFile) - aNeoFile->FTell();
}

int flv_read_header(CNeoFILE* aNeoFile, unsigned char& flags)
{
	unsigned char buff[4];
	unsigned int offset;
	int fsize = filesize(aNeoFile);
	int pos = aNeoFile->FTell();
	if (fsize < 4+1+4)
		return 1;
	aNeoFile->FRead((char*)buff, 4);
	if (buff[0] != 'F' || buff[1] != 'L' || buff[2] != 'V')
		return -1;
	aNeoFile->FRead((char*)buff, 1);
	offset = get_be32(aNeoFile);
	if (fsize < offset)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return 1;
	}
	flags = buff[0];
	aNeoFile->FSeek(offset, SEEK_SET);
	return 0;
}

int flv_read_next_packet(CNeoFILE* aNeoFile, unsigned char* &buff, int& size, int& pts, int& retType, int buff_null)
{
    int type, flags, next, pos;
	
	pos = aNeoFile->FTell();

	aNeoFile->FSeek(4, SEEK_CUR);
	{
		unsigned char val[7];
		aNeoFile->FRead((char*)&val, 7);
		type = val[0];
		size = (val[1] << 16) | (val[2] << 8) | (val[3]);
		pts  = (val[4] << 16) | (val[5] << 8) | (val[6]);
	}
	if (aNeoFile->FEof())
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return -1;
	}
	if (filesize_from_current(aNeoFile) < 4)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return -1;
	}
	aNeoFile->FSeek(4, SEEK_CUR);
	flags = 0;
	
	retType = 0;

	if (size == 0)
		return 0;

	next = size + aNeoFile->FTell();

	if (filesize_from_current(aNeoFile) < size)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return -1;
	}

	if (type == FLV_TAG_TYPE_AUDIO) {
		flags = get_byte(aNeoFile);
		if (buff_null)
			buff = (unsigned char*)malloc(size);
		aNeoFile->FRead((char*)buff, size-1);
		if (aNeoFile->FTell() != next)
			aNeoFile->FSeek(next, SEEK_SET);
		retType = FLV_TAG_TYPE_AUDIO;
		return 0;
	} else if (type == FLV_TAG_TYPE_VIDEO) {
		flags = get_byte(aNeoFile);
		if (buff_null)
			buff = (unsigned char*)malloc(size);
		aNeoFile->FRead((char*)buff, size-1);
		if (aNeoFile->FTell() != next)
			aNeoFile->FSeek(next, SEEK_SET);
		retType = FLV_TAG_TYPE_VIDEO;
	    if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
	    	AddKeyFrame(pts, pos);
		return 0;
	} else if (type == FLV_TAG_TYPE_META) {
		if (size > 13+1+4)
			flv_read_metabody(aNeoFile, next);
		else /* skip packet */
			;
		if (aNeoFile->FTell() != next)
			aNeoFile->FSeek(next, SEEK_SET);
		return 0;
	} else {
		return 0;
	}
}

int flv_read_next_packet_header(CNeoFILE* aNeoFile, int& retType, long& next, int& pts)
{
    int type, pos, size;
	
	pos = aNeoFile->FTell();

	aNeoFile->FSeek(4, SEEK_CUR);
	{
		unsigned char val[7];
		aNeoFile->FRead((char*)&val, 7);
		type = val[0];
		size = (val[1] << 16) | (val[2] << 8) | (val[3]);
		pts  = (val[4] << 16) | (val[5] << 8) | (val[6]);
	}
	if (filesize_from_current(aNeoFile) < size+4)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return -1;
	}
	
	next = size + aNeoFile->FTell() + 4;

	aNeoFile->FSeek(pos, SEEK_SET);
	retType = type;
	return 0;
}

int flv_read_pts(CNeoFILE* aNeoFile, int& pts)
{
	int pos = aNeoFile->FTell();

	if (filesize_from_current(aNeoFile) < 4)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return -1;
	}
	aNeoFile->FSeek(4, SEEK_CUR);
	{
		unsigned char val[7];
		aNeoFile->FRead((char*)&val, 7);
		pts  = (val[4] << 16) | (val[5] << 8) | (val[6]);
	}
	aNeoFile->FSeek(pos, SEEK_SET);
	return 0;
}

int flv_read_if_metabody(CNeoFILE* aNeoFile, int& retType)
{
    int type, next, pos, size;
	
	pos = /*ftell(fp)*/aNeoFile->FTell();
	int fsize_from_current = filesize_from_current(aNeoFile);
	if (fsize_from_current < 15)
		return 1;
	aNeoFile->FSeek(4, SEEK_CUR);
	{
		unsigned char val[7];
		aNeoFile->FRead((char*)&val, 7);
		type = val[0];
		size = (val[1] << 16) | (val[2] << 8) | (val[3]);
	}
	aNeoFile->FSeek(4, SEEK_CUR);

	if (size == 0)
		return 0;

	next = size + aNeoFile->FTell();

	if (filesize(aNeoFile) < next)
	{
		aNeoFile->FSeek(pos, SEEK_SET);
		return 1;
	}

	if (type == FLV_TAG_TYPE_AUDIO) {
		aNeoFile->FSeek(pos, SEEK_SET);
		retType = FLV_TAG_TYPE_AUDIO;
		return 0;
	} else if (type == FLV_TAG_TYPE_VIDEO) {
		aNeoFile->FSeek(pos, SEEK_SET);
		retType = FLV_TAG_TYPE_VIDEO;
		return 0;
	} else if (type == FLV_TAG_TYPE_META) {
		if (size > 13+1+4)
			flv_read_metabody(aNeoFile, next);
		else /* skip packet */
			;
		aNeoFile->FSeek(next, SEEK_SET);
		return 0;
	}	
}

int flv_read_metabody(CNeoFILE* aNeoFile, unsigned int next_pos)
{
	AMFDataType type;
    int keylen;
    char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want.

    keylen = 0;

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

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

    return 0;
}

int flv_find_next_keyframe(CNeoFILE* aNeoFile, int& duration, int& position)
{
    int size, type, flags, next, pos;
	
	pos = aNeoFile->FTell();
	
	while (true)
	{
		position = aNeoFile->FTell();
		aNeoFile->FSeek(4, SEEK_CUR);
		{
			unsigned char val[7];
			aNeoFile->FRead((char*)&val, 7);
			type = val[0];
			size = (val[1] << 16) | (val[2] << 8) | (val[3]);
			duration  = (val[4] << 16) | (val[5] << 8) | (val[6]);
		}
		if (aNeoFile->FEof())
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return -1;
		}
		if (filesize_from_current(aNeoFile) < 4)
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return -1;
		}
		aNeoFile->FSeek(4, SEEK_CUR);
		flags = 0;
		
		if (size == 0)
			continue;
	
		next = size + /*ftell(fp)*/aNeoFile->FTell();
	
		if (filesize_from_current(aNeoFile) < size)
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return -1;
		}
	
		if (type == FLV_TAG_TYPE_AUDIO) {
			flags = get_byte(aNeoFile);
			aNeoFile->FSeek(next, SEEK_SET);
		} else if (type == FLV_TAG_TYPE_VIDEO) {
			flags = get_byte(aNeoFile);
			aNeoFile->FSeek(next, SEEK_SET);
		    if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
		    {
		    	AddKeyFrame(duration, position);
				aNeoFile->FSeek(pos, SEEK_SET);
		    	return 0;
		    }
		} else if (type == FLV_TAG_TYPE_META) {
			aNeoFile->FSeek(next, SEEK_SET);
		}
	}
}

int amf_get_string(CNeoFILE* aNeoFile, char *buffer, int buffsize)
{
    int length = get_be16(aNeoFile);
    if (length >= buffsize) {
		aNeoFile->FSeek(length, SEEK_CUR);
		return -1;
    }

	aNeoFile->FRead(buffer, length);
    buffer[length] = '\0';

    return length;
}

int amf_parse_object(CNeoFILE* aNeoFile, const char *key, unsigned int max_pos, int depth)
{
    AMFDataType amf_type;
    char str_val[256];
    double num_val;

    num_val = 0;

    amf_type = (AMFDataType)get_byte(aNeoFile);

    switch(amf_type) {
        case AMF_DATA_TYPE_NUMBER:
            num_val = av_int2dbl(get_be64(aNeoFile));
			break;
        case AMF_DATA_TYPE_BOOL:
            num_val = get_byte(aNeoFile);
			break;
        case AMF_DATA_TYPE_STRING:
            if(amf_get_string(aNeoFile, str_val, sizeof(str_val)) < 0)
                return -1;
            break;
        case AMF_DATA_TYPE_OBJECT: {
            unsigned int keylen;
            while (aNeoFile->FTell() < max_pos - 2 && (keylen = get_be16(aNeoFile))) {
				aNeoFile->FSeek(keylen, SEEK_CUR);
                if(amf_parse_object(aNeoFile, NULL, max_pos, depth + 1) < 0)
                    return -1; //if we couldn't skip, bomb out.
            }
            if(get_byte(aNeoFile) != 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:
			aNeoFile->FSeek(4, SEEK_CUR);
            while(aNeoFile->FTell() < max_pos - 2 && amf_get_string(aNeoFile, str_val, sizeof(str_val)) > 0) {
                if(amf_parse_object(aNeoFile, str_val, max_pos, depth + 1) < 0)
                    return -1;
            }
            if(get_byte(aNeoFile) != AMF_END_OF_OBJECT)
                return -1;
            break;
        case AMF_DATA_TYPE_ARRAY: {
            unsigned int arraylen, i;
            arraylen = get_be32(aNeoFile);
            for(i = 0; i < arraylen && aNeoFile->FTell() < max_pos - 1; i++) {
                if(amf_parse_object(aNeoFile, NULL, max_pos, depth + 1) < 0)
                    return -1; //if we couldn't skip, bomb out.
            }
        }
            break;
        case AMF_DATA_TYPE_DATE:
			aNeoFile->FSeek(8+2, SEEK_CUR);
            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(!strcmp(key, "duration")) flvGlobalVar.duration = num_val;// * AV_TIME_BASE;
            else if(!strcmp(key, "width") && num_val > 0) flvGlobalVar.width  = num_val;
            else if(!strcmp(key, "height") && num_val > 0) flvGlobalVar.height = num_val;
            if(!strcmp(key, "audiocodecid")) flvGlobalVar.audiocodecid = (int)num_val << FLV_AUDIO_CODECID_OFFSET;//flv_set_audio_codec(astream, (int)num_val << FLV_AUDIO_CODECID_OFFSET);
            else if(!strcmp(key, "videocodecid")) flvGlobalVar.videocodecid = (int)num_val;//flv_set_video_codec(fp, vstream, (int)num_val);
        }

    }

    return 0;
}

unsigned char get_byte(CNeoFILE* aNeoFile)
{
	unsigned char val;
	aNeoFile->FRead((char*)&val, 1);
    return val;
}

unsigned int get_be16(CNeoFILE* aNeoFile)
{
    unsigned int val;
	aNeoFile->FRead((char*)&val, 2);
	val = ((val & 0xFF) << 8) | ((val & 0xFF00) >> 8);
    return val;
}

unsigned int get_be24(CNeoFILE* aNeoFile)
{
    unsigned int val;
	aNeoFile->FRead((char*)&val, 3);
	val = ((val & 0xFF) << 16) | (val & 0xFF00) | ((val & 0xFF0000) >> 16);
    return val;
}

unsigned int get_be32(CNeoFILE *aNeoFile)
{
    unsigned int val;
	aNeoFile->FRead((char*)&val, 4);
	val = ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val & 0xFF0000) >> 8) | ((val & 0xFF000000) >> 24);
    return val;
}

uint64_t get_be64(CNeoFILE* aNeoFile)
{
    uint64_t val;
    val = (uint64_t)get_be32(aNeoFile) << 32;
    val |= (uint64_t)get_be32(aNeoFile);
    return val;
}

double av_int2dbl(int64_t v)
{
    //if(v+v > 0xFFEULL<<52)
    //    return 0.0/0.0;
    return ldexp((double)(((v&((1LL<<52)-1)) + (1LL<<52)) * (v>>63|1)), (v>>52&0x7FF)-1075);
}

TFLVGlobalVar& GetFLVGlobalVar()
{
	return flvGlobalVar;
}

int FLVCalculateFrameRate(CNeoFILE* aNeoFile)
{
	int type, size, next, pts;
	int pos = aNeoFile->FTell();
	int curpos = pos;
	int framecount = 0;

	double FrameTimeStamp = 2000;

	if (flvGlobalVar.framerate > 0)
		return 0;

	next = pos;
	pts = 0;

	if (flvGlobalVar.duration > 0 && flvGlobalVar.duration < 2)
		FrameTimeStamp = flvGlobalVar.duration * 1000;
		
	while (pts < FrameTimeStamp)
	{
		if (aNeoFile->FSize() < next)
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return 1;
		}

		aNeoFile->FSeek(next, SEEK_SET);

		if (filesize_from_current(aNeoFile) < 11)
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return 1;
		}

		curpos = aNeoFile->FTell();
		
		aNeoFile->FSeek(4, SEEK_CUR);
		{
			unsigned char val[7];
			aNeoFile->FRead((char*)&val, 7);
			type = val[0];
			size = (val[1] << 16) | (val[2] << 8) | (val[3]);
			pts  = (val[4] << 16) | (val[5] << 8) | (val[6]);
		}
		
		if (aNeoFile->FEof())
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			if (FrameTimeStamp < 2000 && abs(FrameTimeStamp - pts) < 0.1)
			{
				flvGlobalVar.framerate = framecount*1000/pts;
				return 0;
			}
			return 1;
		}

		if (filesize_from_current(aNeoFile) < 4)
		{
			aNeoFile->FSeek(pos, SEEK_SET);
			return 1;
		}
		aNeoFile->FSeek(4, SEEK_CUR);

		if (size == 0)
			continue;

		if (type == FLV_TAG_TYPE_VIDEO)
			framecount++;

		next = size + /*ftell(fp)*/aNeoFile->FTell();
	}

	aNeoFile->FSeek(pos, SEEK_SET);

	if (pts > 10000)
		return 1;

	flvGlobalVar.framerate = framecount*1000/pts;
	if ( flvGlobalVar.framerate >= 24 && flvGlobalVar.framerate <= 26 )
		flvGlobalVar.framerate = 25;
	if ( flvGlobalVar.framerate >= 29 && flvGlobalVar.framerate <= 31 )
		flvGlobalVar.framerate = 29.97;
	if ( flvGlobalVar.framerate >= 14 && flvGlobalVar.framerate <= 16 )
		flvGlobalVar.framerate = 15;

	if (flvGlobalVar.framerate == 0)
		return 1;	

	return 0;
}

void SetDuration(int duration)
{
	flvGlobalVar.duration = duration;
}

double FLVGetDuration()
{
	return flvGlobalVar.duration;
}

void ResetFrameRateAndCodecID()
{
	flvGlobalVar.framerate = 0;
	flvGlobalVar.audiocodecid = -1;
	flvGlobalVar.videocodecid = -1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -