Exemplo n.º 1
0
// read_header will read all the required information from
// the wtv header/root sections and calculate the skip_chunks.
// If successful, will return with the file positioned
// at the start of the data dir
int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb)
{
	ctx->startbytes_avail = (int)buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);
	return_to_buffer(ctx, ctx->startbytes, ctx->startbytes_avail);

	uint8_t *parsebuf;
	parsebuf = (uint8_t*)malloc(1024);
	buffered_read(ctx, parsebuf,0x42);
	ctx->past+=result;
	if (result!=0x42)
	{
		mprint("\nPremature end of file!\n");
		return CCX_EOF;
	}
	// Expecting WTV header
	if( !memcmp(parsebuf, WTV_HEADER, 16 ) )
	{
		dbg_print(CCX_DMT_PARSE, "\nWTV header\n");
	}
	else
	{
		mprint("\nMissing WTV header. Abort.\n");
		return CCX_EOF;
	}

	//Next read just enough to get the location of the root directory
	uint32_t filelen;
	uint32_t root_dir;
	memcpy(&filelen, parsebuf+0x30, 4);
	dbg_print(CCX_DMT_PARSE, "filelen: %x\n", filelen);
	memcpy(&root_dir, parsebuf+0x38, 4);
	dbg_print(CCX_DMT_PARSE, "root_dir: %x\n", root_dir);

	//Seek to start of the root dir. Typically 0x1100
	buffered_skip(ctx,(root_dir*WTV_CHUNK_SIZE)-0x42);
	ctx->past+=(root_dir*WTV_CHUNK_SIZE)-0x42;

	if (result!=(root_dir*WTV_CHUNK_SIZE)-0x42)
		return CCX_EOF;

	// Read and calculate the meta data chunks in the file we need to skip over
	// while parsing the file.
	int end=0;
	while(!end)
	{
		buffered_read(ctx, parsebuf, 32);
		int x;
		for(x=0; x<16; x++)
			dbg_print(CCX_DMT_PARSE, "%02X ", parsebuf[x]);
		dbg_print(CCX_DMT_PARSE, "\n");

		if (result!=32)
		{
			mprint("\nPremature end of file!\n");
			free(parsebuf);
			return CCX_EOF;
		}
		ctx->past+=32;
		if( !memcmp(parsebuf, WTV_EOF, 16 ))
		{
			dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
			end=1;
		}
		else
		{

			uint16_t len;
			uint64_t file_length;
			memcpy(&len, parsebuf+16, 2);
			dbg_print(CCX_DMT_PARSE, "len: %x\n", len);
			memcpy(&file_length, parsebuf+24, 8);
			dbg_print(CCX_DMT_PARSE, "file_length: %x\n", file_length);
			if(len>1024)
			{
				mprint("Too large for buffer!\n");
				free(parsebuf);
				return CCX_EOF;
			}
			buffered_read(ctx, parsebuf, len-32);
			if (result!=len-32)
			{
				mprint("Premature end of file!\n");
				free(parsebuf);
				return CCX_EOF;
			}
			ctx->past+=len-32;
			// Read a unicode string
			uint32_t text_len;
			memcpy(&text_len, parsebuf, 4); //text_len is number of unicode chars, not bytes.
			dbg_print(CCX_DMT_PARSE, "text_len: %x\n", text_len);
			char *string;
			string = (char*)malloc(text_len+1); // alloc for ascii
			string[text_len]='\0';
			for(x=0; x<text_len; x++)
			{
				memcpy(&string[x], parsebuf+8+(x*2), 1); // unicode converted to ascii
			}
			dbg_print(CCX_DMT_PARSE, "string: %s\n", string);
			// Ignore everything that doesn't contain the text ".entries."
			if(strstr(string, WTV_TABLE_ENTRIES)!=NULL)
			{
				uint32_t value;
				uint32_t flag;
				memcpy(&value, parsebuf+(text_len*2)+8, 4);
				memcpy(&flag, parsebuf+(text_len*2)+4+8, 4);
				dbg_print(CCX_DMT_PARSE, "value: %x\n", value);
				dbg_print(CCX_DMT_PARSE, "flag: %x\n", flag);
				if(!add_skip_chunks(ctx, cb, value, flag))
				{
					mprint("Premature end of file!\n");
					free(parsebuf);
					return CCX_EOF;
				}
			}
			free(string);
		}
	}
	// Our list of skip_chunks is now complete
	// Sort it (not sure if this is needed, but it doesn't hurt).
	qsort(cb->skip_chunks, cb->count, sizeof(uint64_t), qsort_cmpint);
	dbg_print(CCX_DMT_PARSE, "skip_chunks: ");
	int x;
	for(x=0; x<cb->count; x++)
		dbg_print(CCX_DMT_PARSE, "%llx, ", cb->skip_chunks[x]);
	dbg_print(CCX_DMT_PARSE, "\n");

	// Seek forward to the start of the data dir
	// Typically 0x40000
	buffered_skip(ctx,(int)((cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE)-ctx->past));
	cb->filepos=(cb->skip_chunks[cb->chunk]+WTV_META_CHUNK_SIZE);
	cb->chunk++;
	ctx->past=cb->filepos;
	free(parsebuf);
	return CCX_OK;
}
Exemplo n.º 2
0
void detect_stream_type (struct ccx_demuxer *ctx)
{
    ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND; // Not found
    ctx->startbytes_avail = (int) buffered_read_opt(ctx, ctx->startbytes, STARTBYTESLENGTH);

    if( ctx->startbytes_avail == -1)
        fatal (EXIT_READ_ERROR, "Error reading input file!\n");

    if (ctx->startbytes_avail>=4)
    {
        // Check for ASF magic bytes
        if (ctx->startbytes[0]==0x30 &&
                ctx->startbytes[1]==0x26 &&
                ctx->startbytes[2]==0xb2 &&
                ctx->startbytes[3]==0x75)
            ctx->stream_mode=CCX_SM_ASF;
    }
    if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 4)
    {
        if(ctx->startbytes[0]==0xb7 &&
                ctx->startbytes[1]==0xd8 &&
                ctx->startbytes[2]==0x00 &&
                ctx->startbytes[3]==0x20)
            ctx->stream_mode = CCX_SM_WTV;
    }
#ifdef WTV_DEBUG
    if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=6)
    {
        // Check for hexadecimal dump generated by wtvccdump
        // ; CCHD
        if (ctx->startbytes[0]==';' &&
                ctx->startbytes[1]==' ' &&
                ctx->startbytes[2]=='C' &&
                ctx->startbytes[3]=='C' &&
                ctx->startbytes[4]=='H' &&
                ctx->startbytes[5]=='D')
            ctx->stream_mode= CCX_SM_HEX_DUMP;
    }
#endif

    if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail>=11)
    {
        // Check for CCExtractor magic bytes
        if (ctx->startbytes[0]==0xCC &&
                ctx->startbytes[1]==0xCC &&
                ctx->startbytes[2]==0xED &&
                ctx->startbytes[8]==0 &&
                ctx->startbytes[9]==0 &&
                ctx->startbytes[10]==0)
            ctx->stream_mode=CCX_SM_RCWT;
    }
    if ((ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND || ccx_options.print_file_reports)
            && ctx->startbytes_avail >= 4) // Still not found
    {
        long idx = 0, nextBoxLocation = 0, lastBoxLocation = 0;
        int boxScore = 0;
        // Scan the buffer for valid succeeding MP4 boxes.
        while (idx < ctx->startbytes_avail - 7) {
            lastBoxLocation = idx;
            // Check if we have a valid box
            if (isValidMP4Box(ctx->startbytes, idx, &nextBoxLocation, &boxScore))
            {
                idx = nextBoxLocation; // If the box is valid, a new box should be found on the next location... Not somewhere in between.
                if (boxScore > 7)
                {
                    break;
                }
                continue;
            }
            else
            {
                // Not a valid box, reset score. We need a couple of successive boxes to identify a MP4 file.
                boxScore = 0;
                idx++;
            }
        }
        if (boxScore > 1)
        {
            // We had at least one box (or multiple) at the end to "claim" this is MP4. A single valid box at the end is doubtful...
            ctx->stream_mode = CCX_SM_MP4;
        }
    }
    if (ctx->stream_mode==CCX_SM_ELEMENTARY_OR_NOT_FOUND) // Still not found
    {
        if (ctx->startbytes_avail > 188*8) // Otherwise, assume no TS
        {
            // First check for TS
            for (unsigned i=0; i<188; i++)
            {
                if (ctx->startbytes[i]==0x47 && ctx->startbytes[i+188]==0x47 &&
                        ctx->startbytes[i+188*2]==0x47 && ctx->startbytes[i+188*3]==0x47 &&
                        ctx->startbytes[i+188*4]==0x47 && ctx->startbytes[i+188*5]==0x47 &&
                        ctx->startbytes[i+188*6]==0x47 && ctx->startbytes[i+188*7]==0x47
                   )
                {
                    // Eight sync bytes, that's good enough
                    ctx->startbytes_pos=i;
                    ctx->stream_mode=CCX_SM_TRANSPORT;
                    ctx->m2ts = 0;
                    break;
                }
            }
            if (ctx->stream_mode == CCX_SM_TRANSPORT)
            {
                dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as TS\n");
                return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
                return;
            }

            // Check for M2TS
            for (unsigned i = 0; i<192; i++)
            {
                if (ctx->startbytes[i+4] == 0x47 && ctx->startbytes[i + 4 + 192] == 0x47 &&
                        ctx->startbytes[i + 192 * 2+4] == 0x47 && ctx->startbytes[i + 192 * 3+4] == 0x47 &&
                        ctx->startbytes[i + 192 * 4+4] == 0x47 && ctx->startbytes[i + 192 * 5+4] == 0x47 &&
                        ctx->startbytes[i + 192 * 6+4] == 0x47 && ctx->startbytes[i + 192 * 7+4] == 0x47
                   )
                {
                    // Eight sync bytes, that's good enough
                    ctx->startbytes_pos = i;
                    ctx->stream_mode = CCX_SM_TRANSPORT;
                    ctx->m2ts = 1;
                    break;
                }
            }
            if (ctx->stream_mode == CCX_SM_TRANSPORT)
            {
                dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as M2TS\n");
                return_to_buffer (ctx, ctx->startbytes, (unsigned int)ctx->startbytes_avail);
                return;
            }

            // Now check for PS (Needs PACK header)
            for (unsigned i=0;
                    i < (unsigned) (ctx->startbytes_avail<50000?ctx->startbytes_avail-3:49997);
                    i++)
            {
                if (ctx->startbytes[i]==0x00 && ctx->startbytes[i+1]==0x00 &&
                        ctx->startbytes[i+2]==0x01 && ctx->startbytes[i+3]==0xBA)
                {
                    // If we find a PACK header it is not an ES
                    ctx->startbytes_pos=i;
                    ctx->stream_mode=CCX_SM_PROGRAM;
                    break;
                }
            }
            if (ctx->stream_mode == CCX_SM_PROGRAM)
            {
                dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as PS\n");
            }

            // TiVo is also a PS
            if (ctx->startbytes[0]=='T' && ctx->startbytes[1]=='i' &&
                    ctx->startbytes[2]=='V' && ctx->startbytes[3]=='o')
            {
                // The TiVo header is longer, but the PS loop will find the beginning
                dbg_print(CCX_DMT_PARSE, "detect_stream_type: detected as Tivo PS\n");
                ctx->startbytes_pos=187;
                ctx->stream_mode=CCX_SM_PROGRAM;
                strangeheader=1; // Avoid message about unrecognized header
            }
        }
        else
        {
            ctx->startbytes_pos=0;
            ctx->stream_mode=CCX_SM_ELEMENTARY_OR_NOT_FOUND;
        }
    }
    // Don't use STARTBYTESLENGTH. It might be longer than the file length!
    return_to_buffer (ctx, ctx->startbytes, ctx->startbytes_avail);
}