1 /*
2      This file is part of libextractor.
3      Copyright (C) 2004, 2005, 2006, 2009, 2012 Vidyut Samanta and Christian Grothoff
4 
5      libextractor is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9 
10      libextractor is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14 
15      You should have received a copy of the GNU General Public License
16      along with libextractor; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * @file plugins/mpeg_extractor.c
23  * @brief plugin to support MPEG files
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "extractor.h"
28 #include <mpeg2dec/mpeg2.h>
29 
30 
31 /**
32  * Give meta data to extractor.
33  *
34  * @param t type of the meta data
35  * @param s meta data value in utf8 format
36  */
37 #define ADD(s,t) do { if (0 != ec->proc (ec->cls, "mpeg", t, \
38                                          EXTRACTOR_METAFORMAT_UTF8, \
39                                          "text/plain", s, strlen (s) \
40                                          + 1)) goto EXIT; \
41 } while (0)
42 
43 
44 /**
45  * Main entry method for the 'video/mpeg' extraction plugin.
46  *
47  * @param ec extraction context provided to the plugin
48  */
49 void
EXTRACTOR_mpeg_extract_method(struct EXTRACTOR_ExtractContext * ec)50 EXTRACTOR_mpeg_extract_method (struct EXTRACTOR_ExtractContext *ec)
51 {
52   mpeg2dec_t *handle;
53   const mpeg2_info_t *info;
54   void *buf;
55   ssize_t avail;
56   mpeg2_state_t state;
57   char format[256];
58   char lformat[256];
59   char gop_format[256];
60   int have_gop;
61   uint64_t fsize;
62   unsigned int fail_count;
63   int did_seek;
64   int fmt1;
65   int fmt2;
66   int mime;
67   int fpal;
68   int fntsc;
69   int fsecam;
70   int fmac;
71 
72   if (NULL == (handle = mpeg2_init ()))
73     return;
74   if (NULL == (info = mpeg2_info (handle)))
75   {
76     mpeg2_close (handle);
77     return;
78   }
79   fsize = ec->get_size (ec->cls);
80   buf = NULL;
81   have_gop = 0;
82   fail_count = 0;
83   did_seek = 0;
84   fmt1 = 0;
85   fmt2 = 0;
86   mime = 0;
87   fpal = 0;
88   fntsc = 0;
89   fsecam = 0;
90   fmac = 0;
91   lformat[0] = '\0';
92   while (1)
93   {
94     state = mpeg2_parse (handle);
95     switch (state)
96     {
97     case STATE_BUFFER:
98       if (fail_count > 16)
99         goto EXIT; /* do not read large non-mpeg files */
100       fail_count++;
101       if (0 >= (avail = ec->read (ec->cls,
102                                   &buf,
103                                   16 * 1024)))
104         goto EXIT;
105       mpeg2_buffer (handle, buf, buf + avail);
106       break;
107     case STATE_SEQUENCE:
108       fail_count = 0;
109       format[0] = fsize;
110       format[0]++;
111       if (0 == mime)
112       {
113         mime = 1;
114         ADD ("video/mpeg", EXTRACTOR_METATYPE_MIMETYPE);
115       }
116       snprintf (format,
117                 sizeof(format), "%ux%u",
118                 info->sequence->width, info->sequence->height);
119       if (0 != strcmp (lformat,
120                        format))
121       {
122         strcpy (lformat,
123                 format);
124         ADD (format, EXTRACTOR_METATYPE_IMAGE_DIMENSIONS);
125       }
126       switch (info->sequence->flags & SEQ_VIDEO_FORMAT_UNSPECIFIED)
127       {
128       case SEQ_VIDEO_FORMAT_PAL:
129         if (0 == fpal)
130         {
131           fpal = 1;
132           ADD ("PAL", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
133         }
134         break;
135       case SEQ_VIDEO_FORMAT_NTSC:
136         if (0 == fntsc)
137         {
138           fntsc = 1;
139           ADD ("NTSC", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
140         }
141         break;
142       case SEQ_VIDEO_FORMAT_SECAM:
143         if (0 == fsecam)
144         {
145           fsecam = 1;
146           ADD ("SECAM", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
147         }
148         break;
149       case SEQ_VIDEO_FORMAT_MAC:
150         if (0 == fmac)
151         {
152           fmac = 1;
153           ADD ("MAC", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
154         }
155         break;
156       default:
157         break;
158       }
159       if ((info->sequence->flags & SEQ_FLAG_MPEG2) > 0)
160       {
161         if (0 == fmt1)
162         {
163           fmt1 = 1;
164           ADD ("MPEG2", EXTRACTOR_METATYPE_FORMAT_VERSION);
165         }
166       }
167       else
168       {
169         if (0 == fmt2)
170         {
171           fmt2 = 1;
172           ADD ("MPEG1", EXTRACTOR_METATYPE_FORMAT_VERSION);
173         }
174       }
175       if ( (0 == did_seek) &&
176            (fsize != -1) &&
177            (fsize > 1024 * 256 * 2) )
178       {
179         /* skip to the end of the mpeg for speed */
180         did_seek = 1;
181         ec->seek (ec->cls,
182                   fsize - 256 * 1024,
183                   SEEK_SET);
184       }
185       break;
186     case STATE_GOP:
187       fail_count = 0;
188       if ( (NULL != info->gop) &&
189            (0 != info->gop->pictures) )
190       {
191         snprintf (gop_format,
192                   sizeof (gop_format),
193                   "%02u:%02u:%02u (%u frames)",
194                   info->gop->hours,
195                   info->gop->minutes,
196                   info->gop->seconds,
197                   info->gop->pictures);
198         have_gop = 1;
199       }
200       break;
201     case STATE_SLICE:
202       fail_count = 0;
203       break;
204     case STATE_END:
205       fail_count = 0;
206       break;
207     case STATE_INVALID:
208       goto EXIT;
209     default:
210       break;
211     }
212   }
213 EXIT:
214   if (1 == have_gop)
215     ADD (gop_format, EXTRACTOR_METATYPE_DURATION);
216   mpeg2_close (handle);
217 }
218 
219 
220 /* end of mpeg_extractor.c */
221