1 /*
2 * Copyright (C) 2000-2018 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 */
20
21 /*
22 * SMJPEG File Demuxer by Mike Melanson (melanson@pcisys.net)
23 * For more information on the SMJPEG file format, visit:
24 * http://www.lokigames.com/development/smjpeg.php3
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <stdlib.h>
36
37 /********** logging **********/
38 #define LOG_MODULE "demux_smjpeg"
39 /* #define LOG_VERBOSE */
40 /* #define LOG */
41
42 #include <xine/xine_internal.h>
43 #include <xine/xineutils.h>
44 #include <xine/compat.h>
45 #include <xine/demux.h>
46 #include "bswap.h"
47 #include "group_games.h"
48
49 #define FOURCC_TAG BE_FOURCC
50 #define _TXT_TAG FOURCC_TAG('_', 'T', 'X', 'T')
51 #define _SND_TAG FOURCC_TAG('_', 'S', 'N', 'D')
52 #define _VID_TAG FOURCC_TAG('_', 'V', 'I', 'D')
53 #define HEND_TAG FOURCC_TAG('H', 'E', 'N', 'D')
54 #define sndD_TAG FOURCC_TAG('s', 'n', 'd', 'D')
55 #define vidD_TAG FOURCC_TAG('v', 'i', 'd', 'D')
56 #define APCM_TAG FOURCC_TAG('A', 'P', 'C', 'M')
57
58 /* 16 is the max size of a header chunk (the video header) */
59 #define SMJPEG_VIDEO_HEADER_SIZE 16
60 #define SMJPEG_AUDIO_HEADER_SIZE 12
61 #define SMJPEG_HEADER_CHUNK_MAX_SIZE SMJPEG_VIDEO_HEADER_SIZE
62 #define SMJPEG_CHUNK_PREAMBLE_SIZE 12
63
64 typedef struct {
65 demux_plugin_t demux_plugin;
66
67 xine_stream_t *stream;
68 fifo_buffer_t *video_fifo;
69 fifo_buffer_t *audio_fifo;
70 input_plugin_t *input;
71 int status;
72
73 off_t input_length;
74
75 /* video information */
76 unsigned int video_type;
77 xine_bmiheader bih;
78
79 /* audio information */
80 unsigned int audio_type;
81 unsigned int audio_sample_rate;
82 unsigned int audio_bits;
83 unsigned int audio_channels;
84
85 /* playback information */
86 unsigned int duration; /* duration in milliseconds */
87 } demux_smjpeg_t;
88
89
90 /* returns 1 if the SMJPEG file was opened successfully, 0 otherwise */
open_smjpeg_file(demux_smjpeg_t * this)91 static int open_smjpeg_file(demux_smjpeg_t *this) {
92 unsigned int chunk_tag;
93 unsigned char signature[8];
94 unsigned char header_chunk[SMJPEG_HEADER_CHUNK_MAX_SIZE];
95 uint32_t audio_codec = 0;
96
97 static const uint8_t SMJPEG_SIGNATURE[8] =
98 { 0x00, 0x0A, 'S', 'M', 'J', 'P', 'E', 'G' };
99
100 if (_x_demux_read_header(this->input, signature, sizeof(SMJPEG_SIGNATURE)) !=
101 sizeof(SMJPEG_SIGNATURE))
102 return 0;
103
104 if (memcmp(signature, SMJPEG_SIGNATURE, sizeof(SMJPEG_SIGNATURE)) != 0)
105 return 0;
106
107 /* file is qualified; jump over the header + version to the duration */
108 if (this->input->seek(this->input, sizeof(SMJPEG_SIGNATURE) + 4, SEEK_SET) < 0)
109 return 0;
110 if (this->input->read(this->input, header_chunk, 4) != 4)
111 return 0;
112 this->duration = _X_BE_32(&header_chunk[0]);
113
114 /* initial state: no video and no audio (until headers found) */
115 this->video_type = this->audio_type = 0;
116 this->input_length = this->input->get_length (this->input);
117
118 /* traverse the header chunks until the HEND tag is found */
119 chunk_tag = 0;
120 while (chunk_tag != HEND_TAG) {
121
122 if (this->input->read(this->input, header_chunk, 4) != 4)
123 return 0;
124 chunk_tag = _X_BE_32(&header_chunk[0]);
125
126 switch(chunk_tag) {
127
128 case HEND_TAG:
129 /* this indicates the end of the header; do nothing and fall
130 * out of the loop on the next iteration */
131 break;
132
133 case _VID_TAG:
134 if (this->input->read(this->input, header_chunk,
135 SMJPEG_VIDEO_HEADER_SIZE) != SMJPEG_VIDEO_HEADER_SIZE)
136 return 0;
137
138 this->bih.biWidth = _X_BE_16(&header_chunk[8]);
139 this->bih.biHeight = _X_BE_16(&header_chunk[10]);
140 memcpy(&this->bih.biCompression, &header_chunk[12], sizeof(uint32_t));
141 this->video_type = _x_fourcc_to_buf_video(this->bih.biCompression);
142 if (!this->video_type)
143 _x_report_video_fourcc (this->stream->xine, LOG_MODULE, this->bih.biCompression);
144 break;
145
146 case _SND_TAG:
147 if (this->input->read(this->input, header_chunk,
148 SMJPEG_AUDIO_HEADER_SIZE) != SMJPEG_AUDIO_HEADER_SIZE)
149 return 0;
150
151 this->audio_sample_rate = _X_BE_16(&header_chunk[4]);
152 this->audio_bits = header_chunk[6];
153 this->audio_channels = header_chunk[7];
154 /* ADPCM in these files is ID'd by 'APCM' which is used in other
155 * files to denote a slightly different format; thus, use the
156 * following special case */
157 if (_X_BE_32(&header_chunk[8]) == APCM_TAG) {
158 audio_codec = be2me_32(APCM_TAG);
159 this->audio_type = BUF_AUDIO_SMJPEG_IMA;
160 } else {
161 memcpy(&audio_codec, &header_chunk[8], sizeof(uint32_t));
162 this->audio_type = _x_formattag_to_buf_audio(audio_codec);
163 if (!this->audio_type)
164 _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, audio_codec);
165 }
166 break;
167
168 default:
169 /* for all other chunk types, read the length and skip the rest
170 * of the chunk */
171 if (this->input->read(this->input, header_chunk, 4) != 4)
172 return 0;
173 if (this->input->seek(this->input, _X_BE_32(&header_chunk[0]), SEEK_CUR) < 0)
174 return 0;
175 break;
176 }
177 }
178
179 if(!this->video_type)
180 this->video_type = BUF_VIDEO_UNKNOWN;
181
182 if(!this->audio_type && audio_codec)
183 this->audio_type = BUF_AUDIO_UNKNOWN;
184
185 return 1;
186 }
187
demux_smjpeg_send_chunk(demux_plugin_t * this_gen)188 static int demux_smjpeg_send_chunk(demux_plugin_t *this_gen) {
189 demux_smjpeg_t *this = (demux_smjpeg_t *) this_gen;
190
191 buf_element_t *buf = NULL;
192 unsigned int chunk_tag;
193 int64_t pts;
194 unsigned int remaining_sample_bytes;
195 unsigned char preamble[SMJPEG_CHUNK_PREAMBLE_SIZE];
196 off_t current_file_pos;
197 int64_t last_frame_pts = 0;
198 unsigned int audio_frame_count = 0;
199
200 /* load the next sample */
201 current_file_pos = this->input->get_current_pos(this->input);
202 if (this->input->read(this->input, preamble,
203 SMJPEG_CHUNK_PREAMBLE_SIZE) != SMJPEG_CHUNK_PREAMBLE_SIZE) {
204 this->status = DEMUX_FINISHED;
205 return this->status; /* skip to next while() iteration to bail out */
206 }
207
208 chunk_tag = _X_BE_32(&preamble[0]);
209 remaining_sample_bytes = _X_BE_32(&preamble[8]);
210
211 /*
212 * Each sample has an absolute timestamp in millisecond units:
213 *
214 * xine pts timestamp (ms)
215 * -------- = --------------
216 * 90000 1000
217 *
218 * therefore, xine pts = timestamp * 90000 / 1000 => timestamp * 90
219 *
220 * However, millisecond timestamps are not completely accurate
221 * for the audio samples. These audio chunks usually have 256 bytes,
222 * or 512 nibbles, which corresponds to 512 samples.
223 *
224 * 512 samples * (1 sec / 22050 samples) * (1000 ms / 1 sec)
225 * = 23.2 ms
226 *
227 * where the audio samples claim that each chunk is 23 ms long.
228 * Therefore, manually compute the pts values for the audio samples.
229 */
230 if (chunk_tag == sndD_TAG) {
231 pts = audio_frame_count;
232 pts *= 90000;
233 pts /= (this->audio_sample_rate * this->audio_channels);
234 audio_frame_count += ((remaining_sample_bytes - 4) * 2);
235 } else {
236 pts = _X_BE_32(&preamble[4]);
237 pts *= 90;
238 }
239
240 /* break up the data into packets and dispatch them */
241 if (((chunk_tag == sndD_TAG) && this->audio_fifo && this->audio_type) ||
242 (chunk_tag == vidD_TAG)) {
243
244 while (remaining_sample_bytes) {
245 if (chunk_tag == sndD_TAG) {
246 buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
247 buf->type = this->audio_type;
248 } else {
249 buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
250 buf->type = this->video_type;
251 }
252
253 if( this->input_length )
254 buf->extra_info->input_normpos = (int)( (double) current_file_pos * 65535 / this->input_length);
255 buf->extra_info->input_time = pts / 90;
256 buf->pts = pts;
257
258 if (last_frame_pts) {
259 buf->decoder_flags |= BUF_FLAG_FRAMERATE;
260 buf->decoder_info[0] = buf->pts - last_frame_pts;
261 }
262
263 if ((int)remaining_sample_bytes > buf->max_size)
264 buf->size = buf->max_size;
265 else
266 buf->size = remaining_sample_bytes;
267 remaining_sample_bytes -= buf->size;
268
269 if (this->input->read(this->input, buf->content, buf->size) !=
270 buf->size) {
271 buf->free_buffer(buf);
272 this->status = DEMUX_FINISHED;
273 break;
274 }
275
276 /* every frame is a keyframe */
277 buf->decoder_flags |= BUF_FLAG_KEYFRAME;
278 if (!remaining_sample_bytes)
279 buf->decoder_flags |= BUF_FLAG_FRAME_END;
280
281 if (chunk_tag == sndD_TAG)
282 this->audio_fifo->put(this->audio_fifo, buf);
283 else
284 this->video_fifo->put(this->video_fifo, buf);
285 }
286
287 } else {
288
289 /* skip the chunk if it can't be handled */
290 if (this->input->seek(this->input, remaining_sample_bytes, SEEK_CUR) < 0) {
291 this->status = DEMUX_FINISHED;
292 return this->status;
293 }
294 }
295
296 if (chunk_tag == vidD_TAG)
297 last_frame_pts = buf->pts;
298
299 return this->status;
300 }
301
demux_smjpeg_send_headers(demux_plugin_t * this_gen)302 static void demux_smjpeg_send_headers(demux_plugin_t *this_gen) {
303 demux_smjpeg_t *this = (demux_smjpeg_t *) this_gen;
304 buf_element_t *buf;
305
306 this->video_fifo = this->stream->video_fifo;
307 this->audio_fifo = this->stream->audio_fifo;
308
309 this->status = DEMUX_OK;
310
311 /* load stream information */
312 _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
313 _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO,
314 (this->audio_channels) ? 1 : 0);
315 _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH,
316 this->bih.biWidth);
317 _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT,
318 this->bih.biHeight);
319 _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS,
320 this->audio_channels);
321 _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE,
322 this->audio_sample_rate);
323 _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS,
324 this->audio_bits);
325
326 /* send start buffers */
327 _x_demux_control_start(this->stream);
328
329 /* send init info to decoders */
330 buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
331 buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE|
332 BUF_FLAG_FRAME_END;
333 buf->decoder_info[0] = 3000; /* initial video_step */
334 memcpy(buf->content, &this->bih, sizeof(this->bih));
335 buf->size = sizeof(this->bih);
336 buf->type = this->video_type;
337 this->video_fifo->put (this->video_fifo, buf);
338
339 if (this->audio_fifo && this->audio_type) {
340 buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
341 buf->type = this->audio_type;
342 buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
343 buf->decoder_info[0] = 0;
344 buf->decoder_info[1] = this->audio_sample_rate;
345 buf->decoder_info[2] = this->audio_bits;
346 buf->decoder_info[3] = this->audio_channels;
347 this->audio_fifo->put (this->audio_fifo, buf);
348 }
349 }
350
demux_smjpeg_seek(demux_plugin_t * this_gen,off_t start_pos,int start_time,int playing)351 static int demux_smjpeg_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time, int playing) {
352 demux_smjpeg_t *this = (demux_smjpeg_t *) this_gen;
353
354 (void)start_pos;
355 (void)start_time;
356
357 /* if thread is not running, initialize demuxer */
358 if( !playing ) {
359
360 this->status = DEMUX_OK;
361 }
362
363 return this->status;
364 }
365
366
demux_smjpeg_get_status(demux_plugin_t * this_gen)367 static int demux_smjpeg_get_status (demux_plugin_t *this_gen) {
368 demux_smjpeg_t *this = (demux_smjpeg_t *) this_gen;
369
370 return this->status;
371 }
372
demux_smjpeg_get_stream_length(demux_plugin_t * this_gen)373 static int demux_smjpeg_get_stream_length (demux_plugin_t *this_gen) {
374 demux_smjpeg_t *this = (demux_smjpeg_t *) this_gen;
375
376 /* return total running time in miliseconds */
377 return this->duration;
378 }
379
demux_smjpeg_get_capabilities(demux_plugin_t * this_gen)380 static uint32_t demux_smjpeg_get_capabilities(demux_plugin_t *this_gen) {
381 (void)this_gen;
382 return DEMUX_CAP_NOCAP;
383 }
384
demux_smjpeg_get_optional_data(demux_plugin_t * this_gen,void * data,int data_type)385 static int demux_smjpeg_get_optional_data(demux_plugin_t *this_gen,
386 void *data, int data_type) {
387 (void)this_gen;
388 (void)data;
389 (void)data_type;
390 return DEMUX_OPTIONAL_UNSUPPORTED;
391 }
392
open_plugin(demux_class_t * class_gen,xine_stream_t * stream,input_plugin_t * input)393 static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *stream,
394 input_plugin_t *input) {
395
396 demux_smjpeg_t *this;
397
398 if (!INPUT_IS_SEEKABLE(input)) {
399 xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "input not seekable, can not handle!\n");
400 return NULL;
401 }
402
403 this = calloc(1, sizeof(demux_smjpeg_t));
404 if (!this)
405 return NULL;
406
407 this->stream = stream;
408 this->input = input;
409
410 this->demux_plugin.send_headers = demux_smjpeg_send_headers;
411 this->demux_plugin.send_chunk = demux_smjpeg_send_chunk;
412 this->demux_plugin.seek = demux_smjpeg_seek;
413 this->demux_plugin.dispose = default_demux_plugin_dispose;
414 this->demux_plugin.get_status = demux_smjpeg_get_status;
415 this->demux_plugin.get_stream_length = demux_smjpeg_get_stream_length;
416 this->demux_plugin.get_capabilities = demux_smjpeg_get_capabilities;
417 this->demux_plugin.get_optional_data = demux_smjpeg_get_optional_data;
418 this->demux_plugin.demux_class = class_gen;
419
420 this->status = DEMUX_FINISHED;
421
422 switch (stream->content_detection_method) {
423
424 case METHOD_BY_MRL:
425 case METHOD_BY_CONTENT:
426 case METHOD_EXPLICIT:
427
428 if (!open_smjpeg_file(this)) {
429 free (this);
430 return NULL;
431 }
432
433 break;
434
435 default:
436 free (this);
437 return NULL;
438 }
439
440 return &this->demux_plugin;
441 }
442
demux_smjpeg_init_plugin(xine_t * xine,const void * data)443 void *demux_smjpeg_init_plugin (xine_t *xine, const void *data) {
444
445 (void)xine;
446 (void)data;
447
448 static const demux_class_t demux_smjpeg_class = {
449 .open_plugin = open_plugin,
450 .description = N_("SMJPEG file demux plugin"),
451 .identifier = "SMJPEG",
452 .mimetypes = NULL,
453 .extensions = "mjpg",
454 .dispose = NULL,
455 };
456
457 return (void *)&demux_smjpeg_class;
458 }
459