mpeg.c

Go to the documentation of this file.
00001 /* (C) Copyright 2001 by Felix Opatz <felix@zotteljedi.de>
00002  *
00003  * Copyright (c) 2003
00004  *    Felix Opatz <felix@zotteljedi.de>.  All rights reserved.
00005  *
00006  * Copyright (c) 2007
00007  *    Philip Busch <philip@0xe3.com>. All rights reserved.
00008  *
00009  * Reads MPEG frame header information.
00010  * See http://www.dv.co.yu/mpgscript/mpeghdr.htm for MPEG frame header specs.
00011  * See http://www.zotteljedi.de/kleinkram/src/mp3info.c for original version.
00012  *
00013  * Redistribution and use in source and binary forms, with or without
00014  * modification, are permitted provided that the following conditions
00015  * are met:
00016  * 1. Redistributions of source code must retain the above copyright
00017  *    notice, this list of conditions and the following disclaimer as
00018  *    the first lines of this file unmodified.
00019  * 2. Redistributions in binary form must reproduce the above copyright
00020  *    notice, this list of conditions and the following disclaimer in the
00021  *    documentation and/or other materials provided with the distribution.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00024  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00025  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00026  * IN NO EVENT SHALL FELIX OPATZ BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00028  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00029  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00030  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00032  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include "mpeg.h"
00039 
00040 /* some magic numbers, see docs */
00041 static const int bitrates[2][3][15] = {
00042         {
00043                 /* layer 3 */
00044                 {
00045                         0, 32, 40, 48, 56, 64, 80,  96, 112, 128, 160, 192, 224, 256, 320
00046                 },
00047 
00048                 /* layer 2 */
00049                 {
00050                         0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384
00051                 },
00052 
00053                 /* layer 1 */
00054                 {
00055                         0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448
00056                 }
00057         },
00058 
00059         {
00060                 /* layer 3 */
00061                 {
00062                         8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
00063                 },
00064 
00065                 /* layer 2 */
00066                 {
00067                         8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160
00068                 },
00069 
00070                 /* layer 1 */
00071                 {
00072                         0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256
00073                 }
00074         }
00075 };
00076 
00077 static const int freqs[3][3] = {
00078         /* MPEG 1 */
00079         {
00080                 44100, 48000, 32000
00081         },
00082         /* MPEG 2 */
00083         {
00084                 22050, 24000, 16000
00085         },
00086         /* MPEG 2.5 */
00087         {
00088                 11025, 12000, 8000
00089         }
00090 };
00091 
00092 
00093 /* our own ntohl() implementation for strict ANSI compliance */
00094 #ifndef ntohl
00095         #define ntohl own_ntohl
00096 #endif
00097 
00098 static unsigned long int own_ntohl(unsigned long int in)
00099 {
00100         unsigned char a[4], t;
00101 
00102         memcpy(a, &in, 4);
00103 
00104         t = a[3];
00105         a[3] = a[0];
00106         a[0] = t;
00107 
00108         t = a[2];
00109         a[2] = a[1];
00110         a[1] = t;
00111 
00112         memcpy(&in, a, 4);
00113 
00114         return in;
00115 }
00116 
00117 
00118 int mpeg_read(const char *_path, struct mpeg *_mpeg)
00119 {
00120         FILE *fp;
00121         unsigned long int header;
00122 
00123         if ((fp = fopen(_path, "rb")) == NULL) {
00124                 return(-1);
00125         }
00126 
00127         if((header = mpeg_seek_next_header(fp)) == (unsigned long int)-1) {
00128                 return(-1);
00129         }
00130 
00131         if(mpeg_extract_info(header, _mpeg) == -1) {
00132                 return(-1);
00133         }
00134 
00135         fclose(fp);
00136         return(0);
00137 }
00138 
00139 unsigned long int mpeg_seek_next_header(FILE *_fp)
00140 {
00141         unsigned long int header;
00142         int c;
00143 
00144         while((c = fgetc(_fp)) != 0xff && c != EOF);
00145 
00146         if (feof(_fp))
00147                 return(-1);
00148 
00149         ungetc(c, _fp);
00150         fread(&header, 1, sizeof(header), _fp);
00151         header = ntohl(header);
00152 
00153         return(header);
00154 }
00155 
00156 int mpeg_extract_info(unsigned long int _header, struct mpeg *_mpeg)
00157 {
00158         if ((_header & MASK_SYNC) != MASK_SYNC)
00159                 return(-1);
00160 
00161         _mpeg->mpeg_version = ((_header & MASK_MPEG) >> SHIFT_MPEG);
00162 
00163         _mpeg->layer_desc = ((_header & MASK_LAYER) >> SHIFT_LAYER);
00164 
00165         _mpeg->bit_prot = ((_header & MASK_PROT) >> SHIFT_PROT);
00166 
00167         /* causes pain for MPEG_VERSION_2_5 */
00168         _mpeg->bitrate = bitrates[(_mpeg->mpeg_version == MPEG_VERSION_1)?0:1][_mpeg->layer_desc - 1][((_header & MASK_BITRATE) >> SHIFT_BITRATE)];
00169 
00170         switch(_mpeg->mpeg_version)
00171         {
00172                 case MPEG_VERSION_1:
00173                         _mpeg->freq = freqs[0][((_header & MASK_FREQ) >> SHIFT_FREQ)];
00174                         break;
00175                 case MPEG_VERSION_2:
00176                         _mpeg->freq = freqs[1][((_header & MASK_FREQ) >> SHIFT_FREQ)];
00177                         break;
00178                 case MPEG_VERSION_2_5:
00179                         _mpeg->freq = freqs[2][((_header & MASK_FREQ) >> SHIFT_FREQ)];
00180                         break;
00181         }
00182 
00183         _mpeg->bit_padding = ((_header & MASK_PADDING) >> SHIFT_PADDING);
00184 
00185         _mpeg->bit_priv = ((_header & MASK_PRIV) >> SHIFT_PRIV);
00186 
00187         _mpeg->chan = (_header & MASK_CHAN) >> SHIFT_CHAN;
00188 
00189         _mpeg->mode_ext = (_header & MASK_MODE_EXT) >> SHIFT_MODE_EXT;
00190 
00191         _mpeg->bit_copyright = (_header & MASK_COPYRIGHT) >> SHIFT_COPYRIGHT;
00192 
00193         _mpeg->bit_orig = (_header & MASK_ORIG) >> SHIFT_ORIG;
00194 
00195         _mpeg->emphasis = (_header & MASK_EMPHASIS) >> SHIFT_EMPHASIS;
00196 
00197         return(0);
00198 }
00199 
00200 size_t mpeg_frame_length(struct mpeg *_mpeg)
00201 {
00202         int f = (_mpeg->layer_desc == LAYER_VERSION_1)?12:36;
00203 
00204         return(f * _mpeg->bitrate * 1000 / _mpeg->freq + _mpeg->bit_padding);
00205 }
00206 
00207 size_t mpeg_frame_bytes(struct mpeg *_mpeg)
00208 {
00209         return(4 * mpeg_frame_length(_mpeg));
00210 }
00211 
00212 void mpeg_print(struct mpeg *_mpeg)
00213 {
00214         float ver;
00215         int layer;
00216         const char *layers[] = {"I", "II", "III"};
00217         const char *chan_modes[] = {
00218                 "Stereo",
00219                 "Joint stereo (Stereo)",
00220                 "Dual channel (Stereo)",
00221                 "Single channel (Mono)"
00222         };
00223 
00224         const char *emphasis[] = {
00225                 "none",
00226                 "50/15 ms",
00227                 "reserved",
00228                 "CCIT J.17"
00229         };
00230 
00231         if (_mpeg->mpeg_version == MPEG_VERSION_1)
00232                 ver = 1;
00233         if (_mpeg->mpeg_version == MPEG_VERSION_2)
00234                 ver = 2;
00235         if (_mpeg->mpeg_version == MPEG_VERSION_2_5)
00236                 ver = 2.5;
00237 
00238         if (_mpeg->layer_desc == LAYER_VERSION_1)
00239                 layer = 1;
00240         if (_mpeg->layer_desc == LAYER_VERSION_2)
00241                 layer = 2;
00242         if (_mpeg->layer_desc == LAYER_VERSION_3)
00243                 layer = 3;
00244 
00245         printf("MPEG Version %.0f / Layer %s (", ver, layers[layer-1]);
00246 
00247         if (_mpeg->mpeg_version != MPEG_VERSION_2_5)
00248                 printf("%i KBit/s, ", _mpeg->bitrate);
00249 
00250         printf("%i Hz, ", _mpeg->freq);
00251 
00252         printf("%s)\n", chan_modes[_mpeg->chan]);
00253 
00254         printf("Mode extension: ");
00255         if(_mpeg->chan == CMODE_JOINT_STEREO) {
00256                 if(_mpeg->layer_desc == LAYER_VERSION_3) {
00257                         printf("intensity stereo %s, MS stereo %s\n",
00258                                 ((_mpeg->mode_ext==1) || (_mpeg->mode_ext==3))?"on":"off",
00259                                 (_mpeg->mode_ext > 1)?"on":"off"
00260                         );
00261                 } else {
00262                         printf("bands %d to 31\n", (_mpeg->mode_ext + 1) * 4);
00263                 }
00264         } else {
00265                 printf("no mode extension\n");
00266         }
00267 
00268         printf("Emphasis:\t%s\n", emphasis[_mpeg->emphasis]);
00269         printf("Protection:\t%s\n", _mpeg->bit_prot?"no":"yes");
00270         printf("Padding:\t%s\n", _mpeg->bit_padding?"yes":"no");
00271         printf("Private:\t%s\n", _mpeg->bit_priv?"yes":"no");
00272         printf("Copyright:\t%s\n", _mpeg->bit_copyright?"yes":"no");
00273         printf("Original media:\t%s\n", _mpeg->bit_orig?"yes":"no");
00274         
00275         printf("Frame size:\t%d slots (%d bytes)\n", mpeg_frame_length(_mpeg), mpeg_frame_bytes(_mpeg));
00276 }
00277 
00278 int main(int argc, char *argv[])
00279 {
00280         struct mpeg mpeg_data;
00281         int i;
00282 
00283         if (argc < 2) {
00284                 fprintf(stderr, "USAGE: %s <file(s)>\n", argv[0]);
00285                 return 1;
00286         }
00287 
00288         for (i = 1; i < argc; i++) {
00289                 if(mpeg_read(argv[i], &mpeg_data) < 0) {
00290                         fprintf(stderr, "%s: invalid/missing header, ignoring\n",       argv[i]);
00291                 } else {
00292                         printf("MPEG frame header information for %s:\n", argv[i]);
00293                         mpeg_print(&mpeg_data);
00294                 }
00295         }
00296 
00297         return(0);
00298 }

Generated on Thu Jul 19 13:36:09 2007 for libv by  doxygen 1.5.1-p1. Thank you, SourceForge.net Logo