User Tools

Site Tools


tech:multimedia:rmvb
#include <stdio.h>
#include <stdlib.h>
 
#define MKTAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
#define ERROR    do {printf("Error Detected\n"); exit(0);} while(0)
 
#define REALAUDIO_MIME_TYPE		 "audio/x-pn-realaudio"
#define REALVIDEO_MIME_TYPE		 "video/x-pn-realvideo"
 
static int audio_stream = -1;
static int video_stream = -1;
 
 
int rmvb_unpack32(FILE *fp, unsigned int *pVal)
{
    unsigned char buf[4];
 
    if (fread(buf, 1, 4, fp) != 4)
    {
        return -1;
    }
 
    *pVal = (buf[0] << 24)|(buf[1] << 16)|(buf[2] << 8)|buf[3];
    return 0;
}
 
int rmvb_unpack16(FILE *fp, unsigned short *pVal)
{
    unsigned char buf[2];
 
    if (fread(buf, 1, 2, fp) != 2)
    {
        return -1;
    }
 
    *pVal = (buf[0] << 8)|buf[1];
    return 0;
 
}
 
int rmvb_unpack8(FILE *fp, unsigned char *pVal)
{
    *pVal = (unsigned char) fgetc(fp);
 
    if (feof(fp)) 
        return -1;
    else 
        return 0;
}
 
int rmvb_unpack14or30(FILE *fp, unsigned int *pval, unsigned int *len)
{
    unsigned short tmp1;
    unsigned int tmp2;
 
    if (rmvb_unpack16(fp, &tmp1)) return -1;
    if (tmp1&0x4000)
    {
        *pval = tmp1&0x3fff;
        *len = 2;
    }
    else
    {
        fseek(fp, -2, SEEK_CUR);
        if (rmvb_unpack32(fp, &tmp2)) return -1;
        *pval = tmp2&0x3ffffff;
        *len = 4;
    }   
 
    return 0;
}
 
int parse_basic(FILE *fp, unsigned int *pId, unsigned int *pSize, unsigned short *pVersion)
{
    unsigned int size;
    unsigned short version;
 
    if (rmvb_unpack32(fp, pId))
        return -1;
    if (rmvb_unpack32(fp, pSize))
        return -1;
    if (rmvb_unpack16(fp, pVersion))
        return -1;
 
    return 0;
}
 
int parse_indx(FILE *fp, unsigned int size, unsigned short version)
{    
    unsigned int pos = ftell(fp) - 10;
 
    printf("\nINDX Detected @0x%x, size=%u, version = %d\n", pos, size, version);    
 
    fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
int parse_frame(FILE *fp, int size)
{
    unsigned int pos = ftell(fp);
    unsigned short tmp1;
    unsigned char type, seq, tmp2;
    unsigned int size2, time, len, off;
    unsigned char packets, packet;
 
    if (rmvb_unpack16(fp, &tmp1)) return -1;
    type = tmp1 >> 14;
    fseek(fp, -2, SEEK_CUR);
 
    switch(type)
    {
	    /* partial frame */
        case 0:
        case 2:
            if (rmvb_unpack16(fp, &tmp1)) return -1;
            if (rmvb_unpack14or30(fp, &len, &size2)) return -1;
            if (rmvb_unpack14or30(fp, &off, &size2)) return -1;
            if (rmvb_unpack8(fp, &seq)) return -1;
            packets = ((tmp1 & 0x3F80) >> 7);
            packet = (tmp1 & 0x007F);
            printf("\t\t");
            if (packet == 1) putchar('{');
            else putchar('+');
            printf("No.%d (%d-%d), %d@%d", seq, packets, packet, off, len);
            if (packet == packets) putchar('}');
            else putchar('+');
            putchar('\n');
            break;
        case 1:
            if (rmvb_unpack8(fp, &tmp2)) return -1;
            if (rmvb_unpack8(fp, &seq)) return -1;
            printf("\t\t{No.%d}\n", seq);
            break;
        case 3:
            while (size > 0)
            {
                putchar('\t');
                putchar('\t');
                len = 0;
                if (rmvb_unpack8(fp, &tmp2)) return -1;
                if (rmvb_unpack14or30(fp, &size2, &len)) return -1;
                size -= len;
                if (rmvb_unpack14or30(fp, &time, &len)) return -1;
                size -= len;
                if (rmvb_unpack8(fp, &seq)) return -1;
                size -=2;
                printf("{No.%d, size: %d, time: %d},\n", seq, size2, time);
                fseek(fp, size2, SEEK_CUR);
                size -= size2;
			}
            break;
        default:
            break;
    }
 
    fseek(fp, pos+size, SEEK_SET);
    return 0;
}
 
int parse_packet(FILE *fp)
{
    unsigned short version;
    unsigned short size;
    unsigned short stream;
    unsigned int time;
    unsigned char pkt_grp, flags;
    unsigned short asm_rule;
    unsigned int pos = ftell(fp);
 
    if (rmvb_unpack16(fp, &version)) return -1;
    if (rmvb_unpack16(fp, &size)) return -1;
    if (rmvb_unpack16(fp, &stream)) return -1;
    if (rmvb_unpack32(fp, &time)) return -1;
    if (version == 0)
    {
        if (rmvb_unpack8(fp, &pkt_grp)) return -1;
        if (rmvb_unpack8(fp, &flags)) return -1;
    }
    else
    {
        if (rmvb_unpack16(fp, &asm_rule)) return -1;
        if (rmvb_unpack8(fp, &flags)) return -1;   
    }
    printf("stream#%d, size=%d, time:%d\n", stream, size, time);
 
    if (stream == video_stream)
	{
        if (parse_frame(fp, size-12-version)) return -1;
    }
    fseek(fp, pos+size, SEEK_SET);
    return 0;
}
 
int parse_data(FILE *fp, unsigned int size, unsigned short version)
{   
    unsigned int packets;
    unsigned int next;
    unsigned int pos = ftell(fp) - 10;
    int i;
 
    printf("\nDATA Detected @0x%x, size=%u, version = %d\n", pos, size, version);    
 
    if (rmvb_unpack32(fp, &packets)) return -1;
    if (rmvb_unpack32(fp, &next)) return -1;
 
    for (i = 0; i < packets; i++)
    {
        putchar('\t');
        printf("Packet %d: ", i);
        if (parse_packet(fp)) return -1;
    }
 
    if (next)
        fseek(fp, next, SEEK_SET);
    else
        fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
 
int parse_prop(FILE *fp, unsigned int size, unsigned short version)
{
    unsigned int pos = ftell(fp)-10;
    unsigned int v32;
    unsigned short v16;
 
    printf("\nPROP Detected @0x%x, size=%u, version = %d\n", pos, size, version);
    putchar('\t');
    if (version == 0)
    {
        putchar('{');
        putchar(0x20);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("bitrate: %u/", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("packet size: %u/", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u packets; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("duartion=%u ms; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("INDX@0x%x; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("DATA@0x%x; ", v32);
        if (rmvb_unpack16(fp, &v16)) return -1;
        printf("%u streams; ", v16);
        putchar('}');
    }
    putchar('\n');
 
    fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
int parse_mdpr(FILE *fp, unsigned int size, unsigned short version)
{
    unsigned int pos = ftell(fp) - 10;
    unsigned int v32;
    unsigned short v16;
    unsigned char v8;
    char pStr[256];
	int stream_nbr = -1;
 
    printf("\nMDPR Detected @0x%x, size=%u, version = %d\n", pos, size, version);
    putchar('\t');
    if (version == 0)
    {
        putchar('{');
        putchar(0x20);
        if (rmvb_unpack16(fp, &v16)) return -1;
        printf("stream#%d; ", v16);
		stream_nbr = v16;
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("bitrate: %u/", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("packet size: %u/", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u; ", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("time: %u+", v32);
        if (rmvb_unpack32(fp, &v32)) return -1;
        if (rmvb_unpack32(fp, &v32)) return -1;
        printf("%u ms; ", v32);
        if (rmvb_unpack8(fp, &v8) || fread(pStr, 1, v8, fp) != v8) return -1;
        pStr[v8]=0;
        printf("%s; ", pStr);
        if (rmvb_unpack8(fp, &v8) || fread(pStr, 1, v8, fp) != v8) return -1;
        pStr[v8]=0;
        printf("%s; ", pStr);
		if (!strcmp(pStr, REALAUDIO_MIME_TYPE)) audio_stream = stream_nbr;
		if (!strcmp(pStr, REALVIDEO_MIME_TYPE)) video_stream = stream_nbr;
 
        putchar('}');
    }
    putchar('\n');
 
    fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
int parse_cont(FILE *fp, unsigned int size, unsigned short version)
{    
    unsigned int pos = ftell(fp) - 10;
    unsigned short len;
    char *pStr;
    int i;
 
    printf("\nCONT Detected @0x%x, size=%u, version = %d\n", pos, size, version);
    putchar('\t');
    if (version == 0)
    {    
        putchar('{');
        putchar(0x20);
        for (i = 0; i < 4; i++)
        {
            if (rmvb_unpack16(fp, &len)) return -1;
            if (len)
            {
                pStr = (char *)malloc(len+1);
                if (pStr == NULL || fread(pStr, 1, len, fp) != len) return -1;
                pStr[len] = 0;
                printf("%s; ", pStr); 
                free(pStr);
            }
        }
        putchar('}');
    }
    putchar('\n');
 
    fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
int parse_rmmd(FILE *fp, unsigned int size, unsigned short version)
{    
    unsigned int pos = ftell(fp) - 10;
 
    printf("\nRMMD Detected @0x%x, size=%u, version = %d\n", pos, size, version);
 
    fseek(fp, pos+size, SEEK_SET);
 
    return 0;
}
 
 
void parse_rmvb(FILE *fp)
{
    unsigned int id;
    unsigned int size;
    unsigned short version;
    int val;
 
    for (;;)
    {
        if (parse_basic(fp, &id, &size, &version) != 0)
            break;
        switch (id)
        {
            case MKTAG('.', 'R', 'M', 'F'):
                printf("Real Media File Detected: size=%u, version = %d\n", size, version);
                if (rmvb_unpack32(fp, &val)) ERROR;
                printf("File Version: %d\n", val);
                if (rmvb_unpack32(fp, &val)) ERROR;
                printf("number of headers: %d\n", val);
                break;
            case MKTAG('P', 'R', 'O', 'P'):
                if (parse_prop(fp, size, version)) ERROR;
                break;
            case MKTAG('M', 'D', 'P', 'R'):
                if (parse_mdpr(fp, size, version)) ERROR;
                break;
            case MKTAG('C', 'O', 'N', 'T'):
                if (parse_cont(fp, size, version)) ERROR;
                break;
            case MKTAG('D', 'A', 'T', 'A'):
                if (parse_data(fp, size, version)) ERROR;
                break;   
            case MKTAG('I', 'N', 'D', 'X'):
                if (parse_indx(fp, size, version)) ERROR;
                break;    
            case MKTAG('R', 'M', 'M', 'D'):
                if (parse_rmmd(fp, size, version)) ERROR;
                break;                    
            default:
                printf("undefined tag found\n");
                fseek(fp, size-2, SEEK_CUR);
                break;
        }
    }
}
 
int main(int argc, char** argv)
{
    FILE *fp;
    long offset;
 
    if (argc < 2)
    {
        printf("please input file name\n");
        return 0;
    }
 
    fp = fopen(argv[1], "rb");
    if (fp == NULL)
    {
        printf("error in openning file");
        return 0;
    }
    parse_rmvb(fp);
    fclose(fp);	
 
    return 0;
}
tech/multimedia/rmvb.txt · Last modified: 2014/11/10 08:22 (external edit)