/* * fileinfo.c * * Copyright (C) Thomas Oestreich - June 2001 * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "config.h" #ifdef HAVE_LIBDV #include #endif #include #include #include #include #include #include "libtc/libtc.h" #include "libtc/xio.h" #include "ioaux.h" #include "tc.h" /* forward declaration */ static int scan_header_dv(const char *buf); unsigned char asfhdrguid[16]={0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C}; unsigned char mxfmagic[]={0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01}; unsigned char zero_pad[4]={0,0,0,0}; static int cmp_32_bits(char *buf, long x) { if(0) { tc_log_msg(__FILE__, "MAGIC: 0x%02lx 0x%02lx 0x%02lx 0x%02lx %s", (x >> 24) & 0xff, ((x >> 16) & 0xff), ((x >> 8) & 0xff), ((x ) & 0xff), filetype(x)); tc_log_msg(__FILE__, " FILE: 0x%02x 0x%02x 0x%02x 0x%02x", buf[0] & 0xff, buf[1] & 0xff, buf[2] & 0xff, buf[3] & 0xff); } if ((uint8_t)buf[0] != ((x >> 24) & 0xff)) return 0; if ((uint8_t)buf[1] != ((x >> 16) & 0xff)) return 0; if ((uint8_t)buf[2] != ((x >> 8) & 0xff)) return 0; if ((uint8_t)buf[3] != ((x ) & 0xff)) return 0; // OK found it return 1; } static int cmp_28_bits(char *buf, long x) { if(0) { tc_log_msg(__FILE__, "MAGIC: 0x%02lx 0x%02lx 0x%02lx 0x%02lx %s", (x >> 24) & 0xff, ((x >> 16) & 0xff), ((x >> 8) & 0xff), ((x ) & 0xff), filetype(x)); tc_log_msg(__FILE__, " FILE: 0x%02x 0x%02x 0x%02x 0x%02x", buf[0] & 0xff, buf[1] & 0xff, buf[2] & 0xff, buf[3] & 0xff); } if ((uint8_t)buf[0] != ((x >> 24) & 0xff)) return 0; if ((uint8_t)buf[1] != ((x >> 16) & 0xff)) return 0; if ((uint8_t)buf[2] != ((x >> 8) & 0xff)) return 0; if ((uint8_t)(buf[3] & 0xf0) != ((x ) & 0xff)) return 0; // OK found it return 1; } static int cmp_16_bits(char *buf, long x) { int16_t sync_word=0; if(0) { tc_log_msg(__FILE__, "MAGIC: 0x%02lx 0x%02lx 0x%02lx 0x%02lx %s", (x >> 24) & 0xff, ((x >> 16) & 0xff), ((x >> 8) & 0xff), ((x ) & 0xff), filetype(x)); tc_log_msg(__FILE__, " FILE: 0x%02x 0x%02x 0x%02x 0x%02x", buf[0] & 0xff, buf[1] & 0xff, buf[2] & 0xff, buf[3] & 0xff); } sync_word = (sync_word << 8) + (uint8_t) buf[0]; sync_word = (sync_word << 8) + (uint8_t) buf[1]; if(sync_word == (int16_t) x) return 1; // not found; return 0; } static int save_read(char *buf, int bytes, off_t offset, int fdes) { // returns 0 if ok, 1 on failure to read first bytes // rewind if(xio_lseek(fdes, offset, SEEK_SET)<0) { tc_log_warn(__FILE__, "[%s:%d] file seek error: %s", __FILE__, __LINE__, strerror(errno)); return(1); } if(xio_read(fdes, buf, bytes) TC_MAX_SEEK_BYTES) goto exit; if(save_read(buf, 4, off, fdes)) goto exit; } if(off<0) goto exit; //tc_log_msg(__FILE__, "off=%d '%c' '%c' '%c' '%c'", off, buf[0], buf[1], buf[2], buf[3]); /* ------------------------------------------------------------------- * * 2 byte section, read 4 bytes * *-------------------------------------------------------------------*/ if(save_read(buf, 4, off, fdes)) goto exit; // AC3 if(cmp_16_bits(buf, TC_MAGIC_AC3)) { id = TC_MAGIC_AC3; goto exit; } // MP3 audio if(cmp_16_bits(buf, TC_MAGIC_MP3)) { id = TC_MAGIC_MP3; goto exit; } if(cmp_16_bits(buf, TC_MAGIC_MP3_2_5)) { id = TC_MAGIC_MP3_2_5; goto exit; } if(cmp_16_bits(buf, TC_MAGIC_MP3_2)) { id = TC_MAGIC_MP3_2; goto exit; } // MP2 audio if(cmp_16_bits(buf, TC_MAGIC_MP2) || cmp_16_bits(buf, TC_MAGIC_MP2_FC)) { id = TC_MAGIC_MP2; goto exit; } if ( ((((buf[0]<<8)&0xff00)|buf[1])&0xfff8) == 0xfff0) { if ( (buf[1]&0x02) == 0x02) { id = TC_MAGIC_MP3; goto exit; } if ( (buf[1]&0x01) == 0x01) { id = TC_MAGIC_MP2; goto exit; } } // TIFF image if (cmp_16_bits(buf, TC_MAGIC_TIFF1)) { id = TC_MAGIC_TIFF1; goto exit; } if (cmp_16_bits(buf, TC_MAGIC_TIFF2)) { id = TC_MAGIC_TIFF2; goto exit; } // BMP image if (cmp_16_bits(buf, TC_MAGIC_BMP)) { id = TC_MAGIC_BMP; goto exit; } // SGI image if (cmp_16_bits(buf, TC_MAGIC_SGI)) { id = TC_MAGIC_SGI; goto exit; } // PPM image if (strncmp (buf, "P6", 2)==0) { id = TC_MAGIC_PPM; goto exit; } // PGM image if (strncmp (buf, "P5", 2)==0) { id = TC_MAGIC_PGM; goto exit; } // SGI image if (cmp_16_bits(buf, TC_MAGIC_SGI)) { id = TC_MAGIC_SGI; goto exit; } // transport stream if (buf[0] == (uint8_t) TC_MAGIC_TS) { id = TC_MAGIC_TS; goto exit; } /* ------------------------------------------------------------------- * * 4 byte section * *-------------------------------------------------------------------*/ if(save_read(buf, 4, off, fdes)) goto exit; // DTS if(cmp_32_bits(buf, TC_MAGIC_DTS)) { id = TC_MAGIC_DTS; goto exit; } // VOB if(cmp_32_bits(buf, TC_MAGIC_VOB)) { id = TC_MAGIC_VOB; goto exit; } // MPEG Video / .VDR if(cmp_28_bits(buf, TC_MAGIC_MPEG)) { id = TC_MAGIC_MPEG; /* FIXME: it's PES? */ goto exit; } // DV if(cmp_32_bits(buf, TC_MAGIC_DV_NTSC)) { id = TC_MAGIC_DV_NTSC; goto exit; } // DV if(cmp_32_bits(buf, TC_MAGIC_DV_PAL)) { id = TC_MAGIC_DV_PAL; goto exit; } // OGG stream if (strncmp (buf, "OggS", 4)==0) { id = TC_MAGIC_OGG; goto exit; } // M2V if(cmp_32_bits(buf, TC_MAGIC_M2V)) { id = TC_MAGIC_MPEG_ES; goto exit; } // NUV if(cmp_32_bits(buf, TC_MAGIC_NUV)) { id = TC_MAGIC_NUV; goto exit; } // OGG if (strncasecmp(buf, "OggS", 4) == 0) { id = TC_MAGIC_OGG; goto exit; } // Real Media if(strncasecmp(buf,".RMF", 4)==0) { id = TC_MAGIC_RMF; goto exit; } // PV3 if (memcmp(buf, "PV3\1", 4) == 0 || memcmp(buf, "PV3\2", 4) == 0) { id = TC_MAGIC_PV3; goto exit; } // PVN if (buf[0]=='P' && buf[1]=='V' && (buf[2]>='4' && buf[2]<='6') && (buf[3]=='a' || buf[3]=='b' || buf[3]=='d' || buf[3]=='f') ) { id = TC_MAGIC_PVN; goto exit; } // MP3 audio + odd 0 padding if(cmp_16_bits(buf+1, TC_MAGIC_MP3)) { id = TC_MAGIC_MP3; goto exit; } if(cmp_16_bits(buf+1, TC_MAGIC_MP3_2_5)) { id = TC_MAGIC_MP3_2_5; goto exit; } if(cmp_16_bits(buf+1, TC_MAGIC_MP3_2)) { id = TC_MAGIC_MP3_2; goto exit; } if(cmp_16_bits(buf+2, TC_MAGIC_MP3)) { id = TC_MAGIC_MP3; goto exit; } if(cmp_16_bits(buf+2, TC_MAGIC_MP3_2_5)) { id = TC_MAGIC_MP3_2_5; goto exit; } if(cmp_16_bits(buf+2, TC_MAGIC_MP3_2)) { id = TC_MAGIC_MP3_2; goto exit; } if(cmp_32_bits(buf, TC_MAGIC_ID3)) { id = TC_MAGIC_ID3; goto exit; } // iTunes sets an ID3 header that way at the beginning. We search for an // syncword first so it should just work. if (buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3' && buf[3] == 0x02) { id = TC_MAGIC_MP3; goto exit; } /* ------------------------------------------------------------------- * * 8 byte section * *-------------------------------------------------------------------*/ if(save_read(buf, 8, off, fdes)) goto exit; // YUV4MPEG if (strncmp (buf, "YUV4MPEG", 8)==0) { id = TC_MAGIC_YUV4MPEG; goto exit; } // BSDAV if (strncmp (buf, "BSDAV", 5)==0) { id = TC_MAGIC_BSDAV; goto exit; } // MOV if(strncasecmp(buf+4,"moov", 4) ==0 || strncasecmp(buf+4,"cmov", 4) ==0 || strncasecmp(buf+4,"mdat", 4) ==0 || strncasecmp(buf+4,"ftyp", 4) ==0 || strncasecmp(buf+4,"pnot", 4) ==0) { id = TC_MAGIC_MOV; goto exit; } // PNG if (cmp_32_bits(buf, TC_MAGIC_PNG) && cmp_32_bits(buf+4, 0x0D0A1A0A)) { id = TC_MAGIC_PNG; goto exit; } // GIF if (strncasecmp(buf, "GIF87a", 6) == 0 || strncasecmp(buf, "GIF89a", 6) == 0) { id = TC_MAGIC_GIF; goto exit; } // XML if(strncasecmp(buf,"prev_frame_decoded = 0; cc = dv_parse_header(dv_decoder, buf); dv_decoder_free(dv_decoder); #endif return(cc); }