1 /*
2  * MNG file demuxer for MPlayer
3  *
4  * Copyright (C) 2008 Stefan Schuermans <stefan blinkenarea org>
5  *
6  * This file is part of MPlayer.
7  *
8  * MPlayer is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * MPlayer is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 
27 #include "config.h"
28 
29 #include "mp_msg.h"
30 #include "help_mp.h"
31 
32 #include "stream/stream.h"
33 #include "demuxer.h"
34 #include "stheader.h"
35 
36 #define MNG_NO_INCLUDE_JNG
37 #define MNG_SUPPORT_READ
38 #define MNG_SUPPORT_DISPLAY
39 #include <libmng.h>
40 
41 /**
42  * \brief some small fixed start time > 0
43  *
44  * Start time must be > 0 for the variable frame time mechanism
45  * (GIF, MATROSKA, MNG) in video.c to work for the first frame.
46  */
47 #define MNG_START_PTS 0.01f
48 
49 /**
50  * \brief private context structure
51  *
52  * This structure is used as private data for MPlayer demuxer
53  * and also as private data for the MNG library.
54  *
55  * All members ending in \p _ms are in milliseconds
56  */
57 typedef struct {
58     stream_t * stream;          ///< pointer to MNG data input stream
59     mng_handle h_mng;           ///< MNG library image handle
60     int header_processed;       ///< if MNG image header is processed
61     mng_uint32 width;           ///< MNG image width
62     mng_uint32 height;          ///< MNG image height
63     int total_time_ms;          ///< total MNG animation time
64     unsigned char * canvas;     /**< \brief canvas to draw the image onto
65                                  *   \details
66                                  *   \li lines top-down
67                                  *   \li pixels left-to-right
68                                  *   \li channels RGB
69                                  *   \li no padding
70                                  *   \li NULL if no canvas yet
71                                  */
72     int displaying;             /**< \brief if displaying already,
73                                  *          i.e. if mng_display has
74                                  *          already been called
75                                  */
76     int finished;               ///< if animation is finished
77     int global_time_ms;         ///< current global time for MNG library
78     int anim_cur_time_ms;       ///< current frame time in MNG animation
79     int anim_frame_duration_ms; ///< current frame duration in MNG animation
80     int show_cur_time_ms;       /**< \brief current time in the show process,
81                                  *          i.e. time of last demux packet
82                                  */
83     int show_next_time_ms;      /**< \brief next time in the show process,
84                                  *          i.e. time of next demux packet
85                                  */
86     int timer_ms;               /**< \brief number of milliseconds after which
87                                  *          libmng wants to be called again
88                                  */
89 } mng_priv_t;
90 
91 /**
92  * \brief MNG library callback: Allocate a new zero-filled memory block.
93  * \param[in] size memory block size
94  * \return pointer to new memory block
95  */
demux_mng_alloc(mng_size_t size)96 static mng_ptr demux_mng_alloc(mng_size_t size)
97 {
98     return calloc(1, size);
99 }
100 
101 /**
102  * \brief MNG library callback: Free memory block.
103  * \param[in] ptr pointer to memory block
104  * \param[in] size memory block size
105  */
demux_mng_free(mng_ptr ptr,mng_size_t size)106 static void demux_mng_free(mng_ptr ptr, mng_size_t size)
107 {
108     free(ptr);
109 }
110 
111 /**
112  * \brief MNG library callback: Open MNG stream.
113  * \param[in] h_mng MNG library image handle
114  * \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
115  */
demux_mng_openstream(mng_handle h_mng)116 static mng_bool demux_mng_openstream(mng_handle h_mng)
117 {
118     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
119     stream_t * stream = mng_priv->stream;
120 
121     // rewind stream to the beginning
122     stream_seek(stream, stream->start_pos);
123 
124     return MNG_TRUE;
125 }
126 
127 /**
128  * \brief MNG library callback: Close MNG stream.
129  * \param[in] h_mng MNG library image handle
130  * \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
131  */
demux_mng_closestream(mng_handle h_mng)132 static mng_bool demux_mng_closestream(mng_handle h_mng)
133 {
134     return MNG_TRUE;
135 }
136 
137 /**
138  * \brief MNG library callback: Read data from stream.
139  * \param[in] h_mng MNG library image handle
140  * \param[in] buf pointer to buffer to fill with data
141  * \param[in] size size of buffer
142  * \param[out] read number of bytes read from stream
143  * \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
144  */
demux_mng_readdata(mng_handle h_mng,mng_ptr buf,mng_uint32 size,mng_uint32 * read)145 static mng_bool demux_mng_readdata(mng_handle h_mng, mng_ptr buf,
146                                    mng_uint32 size, mng_uint32 * read)
147 {
148     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
149     stream_t * stream = mng_priv->stream;
150 
151     // simply read data from stream and return number of bytes or error
152     *read = stream_read(stream, buf, size);
153 
154     return MNG_TRUE;
155 }
156 
157 /**
158  * \brief MNG library callback: Header information is processed now.
159  * \param[in] h_mng MNG library image handle
160  * \param[in] width image width
161  * \param[in] height image height
162  * \return \p MNG_TRUE on success, \p MNG_FALSE on error
163  */
demux_mng_processheader(mng_handle h_mng,mng_uint32 width,mng_uint32 height)164 static mng_bool demux_mng_processheader(mng_handle h_mng, mng_uint32 width,
165                                         mng_uint32 height)
166 {
167     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
168 
169     // remember size in private data
170     mng_priv->header_processed = 1;
171     mng_priv->width            = width;
172     mng_priv->height           = height;
173 
174     // get total animation time
175     mng_priv->total_time_ms = mng_get_playtime(h_mng);
176 
177     // allocate canvas
178     mng_priv->canvas = malloc(height * width * 4);
179     if (!mng_priv->canvas) {
180         mp_msg(MSGT_DEMUX, MSGL_ERR,
181                "demux_mng: could not allocate canvas of size %dx%d\n",
182                width, height);
183         return MNG_FALSE;
184     }
185 
186     return MNG_TRUE;
187 }
188 
189 /**
190  * \brief MNG library callback: Get access to a canvas line.
191  * \param[in] h_mng MNG library image handle
192  * \param[in] line y coordinate of line to access
193  * \return pointer to line on success, \p MNG_NULL on error
194  */
demux_mng_getcanvasline(mng_handle h_mng,mng_uint32 line)195 static mng_ptr demux_mng_getcanvasline(mng_handle h_mng, mng_uint32 line)
196 {
197     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
198 
199     // return pointer to canvas line
200     if (line < mng_priv->height && mng_priv->canvas)
201         return (mng_ptr)(mng_priv->canvas + line * mng_priv->width * 4);
202     else
203         return (mng_ptr)MNG_NULL;
204 }
205 
206 /**
207  * \brief MNG library callback: A part of the canvas should be shown.
208  *
209  * This function is called by libmng whenever it thinks a
210  * rectangular part of the display should be updated. This
211  * can happen multiple times for a frame and/or a single time
212  * for a frame. Only the the part of the display occupied by
213  * the rectangle defined by x, y, width, height is to be updated.
214  * It is possible that some parts of the display are not updated
215  * for many frames. There is no chance here to find out if the
216  * current frame is completed with this update or not.
217  *
218  * This mechanism does not match MPlayer's demuxer architecture,
219  * so it will not be used exactly as intended by libmng.
220  * A new frame is generated in the demux_mng_fill_buffer() function
221  * whenever libmng tells us to wait for some time.
222  *
223  * \param[in] h_mng MNG library image handle
224  * \param[in] x rectangle's left edge
225  * \param[in] y rectangle's top edge
226  * \param[in] width rectangle's width
227  * \param[in] height rectangle's heigt
228  * \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
229  */
demux_mng_refresh(mng_handle h_mng,mng_uint32 x,mng_uint32 y,mng_uint32 width,mng_uint32 height)230 static mng_bool demux_mng_refresh(mng_handle h_mng, mng_uint32 x, mng_uint32 y,
231                                   mng_uint32 width, mng_uint32 height)
232 {
233     // nothing to do here, the image data is already on the canvas
234     return MNG_TRUE;
235 }
236 
237 /**
238  * \brief MNG library callback: Get how many milliseconds have passed.
239  * \param[in] h_mng MNG library image handle
240  * \return global time in milliseconds
241  */
demux_mng_gettickcount(mng_handle h_mng)242 static mng_uint32 demux_mng_gettickcount(mng_handle h_mng)
243 {
244     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
245 
246     // return current global time
247     return mng_priv->global_time_ms;
248 }
249 
250 /**
251  * \brief MNG library callback: Please call again after some milliseconds.
252  * \param[in] h_mng MNG library image handle
253  * \param[in] msecs number of milliseconds after which to call again
254  * \return \p MNG_TRUE on success, \p MNG_FALSE on error (never happens)
255  */
demux_mng_settimer(mng_handle h_mng,mng_uint32 msecs)256 static mng_bool demux_mng_settimer(mng_handle h_mng, mng_uint32 msecs)
257 {
258     mng_priv_t * mng_priv = mng_get_userdata(h_mng);
259 
260     // Save number of milliseconds after which to call the MNG library again
261     // in private data.
262     mng_priv->timer_ms = msecs;
263     return MNG_TRUE;
264 }
265 
266 /**
267  * \brief MPlayer callback: Check if stream contains MNG data.
268  * \param[in] demuxer demuxer structure
269  * \return demuxer type constant, \p 0 if unknown
270  */
demux_mng_check_file(demuxer_t * demuxer)271 static int demux_mng_check_file(demuxer_t *demuxer)
272 {
273     char buf[4];
274     if (stream_read(demuxer->stream, buf, 4) != 4)
275         return 0;
276     if (memcmp(buf, "\x8AMNG", 4))
277         return 0;
278     return DEMUXER_TYPE_MNG;
279 }
280 
281 /**
282  * \brief MPlayer callback: Fill buffer from MNG stream.
283  * \param[in] demuxer demuxer structure
284  * \param[in] ds demuxer stream
285  * \return \p 1 on success, \p 0 on error
286  */
demux_mng_fill_buffer(demuxer_t * demuxer,demux_stream_t * ds)287 static int demux_mng_fill_buffer(demuxer_t * demuxer,
288                                  demux_stream_t * ds)
289 {
290     mng_priv_t * mng_priv = demuxer->priv;
291     mng_handle h_mng = mng_priv->h_mng;
292     mng_retcode mng_ret;
293     demux_packet_t * dp;
294 
295     // exit if animation is finished
296     if (mng_priv->finished)
297         return 0;
298 
299     // advance animation to requested next show time
300     while (mng_priv->anim_cur_time_ms + mng_priv->anim_frame_duration_ms
301            <= mng_priv->show_next_time_ms && !mng_priv->finished) {
302 
303         // advance global and animation time
304         mng_priv->global_time_ms += mng_priv->anim_frame_duration_ms;
305         mng_priv->anim_cur_time_ms += mng_priv->anim_frame_duration_ms;
306 
307         // Clear variable MNG library will write number of milliseconds to
308         // (via settimer callback).
309         mng_priv->timer_ms = 0;
310 
311         // get next image from MNG library
312         if (mng_priv->displaying)
313             mng_ret = mng_display_resume(h_mng); // resume displaying MNG data
314                                                  // to canvas
315         else
316             mng_ret = mng_display(h_mng); // start displaying MNG data to canvas
317         if (mng_ret && mng_ret != MNG_NEEDTIMERWAIT) {
318             mp_msg(MSGT_DEMUX, MSGL_ERR,
319                    "demux_mng: could not display MNG data to canvas: "
320                    "mng_retcode %d\n", mng_ret);
321             return 0;
322         }
323         mng_priv->displaying = 1; // mng_display() has been called now
324         mng_priv->finished   = mng_ret == 0; // animation is finished iff
325                                              // mng_display() returned 0
326 
327         // save current frame duration
328         mng_priv->anim_frame_duration_ms = mng_priv->timer_ms < 1
329                                            ? 1 : mng_priv->timer_ms;
330 
331     } // while (mng_priv->anim_cur_time_ms + ...
332 
333     // create a new demuxer packet
334     dp = new_demux_packet(mng_priv->height * mng_priv->width * 4);
335 
336     // copy image data into demuxer packet
337     memcpy(dp->buffer, mng_priv->canvas,
338            mng_priv->height * mng_priv->width * 4);
339 
340     // set current show time to requested show time
341     mng_priv->show_cur_time_ms = mng_priv->show_next_time_ms;
342 
343     // get time of next frame to show
344     mng_priv->show_next_time_ms = mng_priv->anim_cur_time_ms
345                                 + mng_priv->anim_frame_duration_ms;
346 
347     // Set position and timing information in demuxer video and demuxer packet.
348     //  - Time must be time of next frame and always be > 0 for the variable
349     //    frame time mechanism (GIF, MATROSKA, MNG) in video.c to work.
350     demuxer->video->dpos++;
351     dp->pts = (float)mng_priv->show_next_time_ms / 1000.0f + MNG_START_PTS;
352     dp->pos = stream_tell(demuxer->stream);
353     ds_add_packet(demuxer->video, dp);
354 
355     return 1;
356 }
357 
358 /**
359  * \brief MPlayer callback: Open MNG stream.
360  * \param[in] demuxer demuxer structure
361  * \return demuxer structure on success, \p NULL on error
362  */
demux_mng_open(demuxer_t * demuxer)363 static demuxer_t * demux_mng_open(demuxer_t * demuxer)
364 {
365     mng_priv_t * mng_priv;
366     mng_handle h_mng;
367     mng_retcode mng_ret;
368     sh_video_t * sh_video;
369 
370     // create private data structure
371     mng_priv = calloc(1, sizeof(mng_priv_t));
372 
373     //stream pointer into private data
374     mng_priv->stream = demuxer->stream;
375 
376     // initialize MNG image instance
377     h_mng = mng_initialize((mng_ptr)mng_priv, demux_mng_alloc,
378                            demux_mng_free, MNG_NULL);
379     if (!h_mng) {
380         mp_msg(MSGT_DEMUX, MSGL_ERR,
381                "demux_mng: could not initialize MNG image instance\n");
382         free(mng_priv);
383         return NULL;
384     }
385 
386     // MNG image handle into private data
387     mng_priv->h_mng = h_mng;
388 
389     // set required MNG callbacks
390     if (mng_setcb_openstream(h_mng, demux_mng_openstream) ||
391         mng_setcb_closestream(h_mng, demux_mng_closestream) ||
392         mng_setcb_readdata(h_mng, demux_mng_readdata) ||
393         mng_setcb_processheader(h_mng, demux_mng_processheader) ||
394         mng_setcb_getcanvasline(h_mng, demux_mng_getcanvasline) ||
395         mng_setcb_refresh(h_mng, demux_mng_refresh) ||
396         mng_setcb_gettickcount(h_mng, demux_mng_gettickcount) ||
397         mng_setcb_settimer(h_mng, demux_mng_settimer) ||
398         mng_set_canvasstyle(h_mng, MNG_CANVAS_RGBA8)) {
399         mp_msg(MSGT_DEMUX, MSGL_ERR,
400                "demux_mng: could not set MNG callbacks\n");
401         mng_cleanup(&h_mng);
402         free(mng_priv);
403         return NULL;
404     }
405 
406     // start reading MNG data
407     mng_ret = mng_read(h_mng);
408     if (mng_ret) {
409         mp_msg(MSGT_DEMUX, MSGL_ERR,
410                "demux_mng: could not start reading MNG data: "
411                "mng_retcode %d\n", mng_ret);
412         mng_cleanup(&h_mng);
413         free(mng_priv);
414         return NULL;
415     }
416 
417     // check that MNG header is processed now
418     if (!mng_priv->header_processed) {
419         mp_msg(MSGT_DEMUX, MSGL_ERR,
420                "demux_mng: internal error: header not processed\n");
421         mng_cleanup(&h_mng);
422         free(mng_priv);
423         return NULL;
424     }
425 
426     // create a new video stream header
427     sh_video = new_sh_video(demuxer, 0);
428 
429     // Make sure the demuxer knows about the new video stream header
430     // (even though new_sh_video() ought to take care of it).
431     // (Thanks to demux_gif.c for this.)
432     demuxer->video->id = 0;
433     demuxer->video->sh = sh_video;
434 
435     // set format of pixels in video packets
436     sh_video->format = mmioFOURCC(32, 'B', 'G', 'R');
437 
438     // set framerate to some value (MNG does not have a fixed framerate)
439     sh_video->fps       = 5.0f;
440     sh_video->frametime = 1.0f / sh_video->fps;
441 
442     // set video frame parameters
443     sh_video->bih                = malloc(sizeof(*sh_video->bih));
444     sh_video->bih->biCompression = sh_video->format;
445     sh_video->bih->biWidth       = mng_priv->width;
446     sh_video->bih->biHeight      = mng_priv->height;
447     sh_video->bih->biBitCount    = 32;
448     sh_video->bih->biPlanes      = 1;
449 
450     // Set start time to something > 0.
451     //  - This is required for the variable frame time mechanism
452     //    (GIF, MATROSKA, MNG) in video.c to work for the first frame.
453     sh_video->ds->pts = MNG_START_PTS;
454 
455     // set private data in demuxer and return demuxer
456     demuxer->priv = mng_priv;
457     return demuxer;
458 }
459 
460 /**
461  * \brief MPlayer callback: Close MNG stream.
462  * \param[in] demuxer demuxer structure
463  */
demux_mng_close(demuxer_t * demuxer)464 static void demux_mng_close(demuxer_t* demuxer)
465 {
466     mng_priv_t * mng_priv = demuxer->priv;
467 
468     if (mng_priv) {
469 
470         // shutdown MNG image instance
471         if (mng_priv->h_mng)
472             mng_cleanup(&mng_priv->h_mng);
473 
474         // free private data
475         free(mng_priv->canvas);
476 
477         free(mng_priv);
478     }
479 }
480 
481 /**
482  * \brief MPlayer callback: Seek in MNG stream.
483  * \param[in] demuxer demuxer structure
484  * \param[in] rel_seek_secs relative seek time in seconds
485  * \param[in] audio_delay unused, MNG does not contain audio
486  * \param[in] flags bit flags, \p 1: absolute, \p 2: fractional position
487  */
demux_mng_seek(demuxer_t * demuxer,float rel_seek_secs,float audio_delay,int flags)488 static void demux_mng_seek(demuxer_t * demuxer, float rel_seek_secs,
489                            float audio_delay, int flags)
490 {
491     mng_priv_t * mng_priv = demuxer->priv;
492     mng_handle h_mng = mng_priv->h_mng;
493     mng_retcode mng_ret;
494     int seek_ms, pos_ms;
495 
496     // exit if not ready to seek (header not yet read or not yet displaying)
497     if (!mng_priv->header_processed || !mng_priv->displaying)
498         return;
499 
500     // get number of milliseconds to seek to
501     if (flags & 2) // seek by fractional position (0.0 ... 1.0)
502         seek_ms = (int)(rel_seek_secs * (float)mng_priv->total_time_ms);
503     else // seek by time in seconds
504         seek_ms = (int)(rel_seek_secs * 1000.0f + 0.5f);
505 
506     // get new position in milliseconds
507     if (flags & 1) // absolute
508         pos_ms = seek_ms;
509     else // relative
510         pos_ms = mng_priv->show_cur_time_ms + seek_ms;
511 
512     // fix position
513     if (pos_ms < 0)
514         pos_ms = 0;
515     if (pos_ms > mng_priv->total_time_ms)
516         pos_ms = mng_priv->total_time_ms;
517 
518     // FIXME
519     // In principle there is a function to seek in MNG: mng_display_gotime().
520     //  - Using it did not work out (documentation is very brief,
521     //    example code does not exist?).
522     //  - The following code works, but its performance is quite bad.
523 
524     // seeking forward
525     if (pos_ms >= mng_priv->show_cur_time_ms) {
526 
527         // Simply advance show time to seek position.
528         //  - Everything else will be handled in demux_mng_fill_buffer().
529         mng_priv->show_next_time_ms = pos_ms;
530 
531     } // if (pos_ms > mng_priv->show_time_ms)
532 
533     // seeking backward
534     else { // if (pos_ms > mng_priv->show_time_ms)
535 
536         // Clear variable MNG library will write number of milliseconds to
537         // (via settimer callback).
538         mng_priv->timer_ms = 0;
539 
540         // Restart displaying and advance show time to seek position.
541         //  - Everything else will be handled in demux_mng_fill_buffer().
542         mng_ret = mng_display_reset(h_mng);
543         // If a timer wait is needed, fool libmng that requested time
544         // passed and try again.
545         if (mng_ret == MNG_NEEDTIMERWAIT) {
546             mng_priv->global_time_ms += mng_priv->timer_ms;
547             mng_ret = mng_display_reset(h_mng);
548         }
549         if (mng_ret) {
550             mp_msg(MSGT_DEMUX, MSGL_ERR,
551                    "demux_mng: could not reset MNG display state: "
552                    "mng_retcode %d\n", mng_ret);
553             return;
554         }
555         mng_priv->displaying             = 0;
556         mng_priv->finished               = 0;
557         mng_priv->anim_cur_time_ms       = 0;
558         mng_priv->anim_frame_duration_ms = 0;
559         mng_priv->show_next_time_ms      = pos_ms;
560 
561     } // if (pos_ms > mng_priv->show_time_ms) ... else
562 }
563 
564 /**
565  * \brief MPlayer callback: Control MNG stream.
566  * \param[in] demuxer demuxer structure
567  * \param[in] cmd code of control command to perform
568  * \param[in,out] arg command argument
569  * \return demuxer control response code
570  */
demux_mng_control(demuxer_t * demuxer,int cmd,void * arg)571 static int demux_mng_control(demuxer_t * demuxer, int cmd, void * arg)
572 {
573     mng_priv_t * mng_priv = demuxer->priv;
574 
575     switch(cmd) {
576 
577       // get total movie length
578       case DEMUXER_CTRL_GET_TIME_LENGTH:
579           if (mng_priv->header_processed) {
580               *(double *)arg = (double)mng_priv->total_time_ms / 1000.0;
581               return DEMUXER_CTRL_OK;
582           } else {
583               return DEMUXER_CTRL_DONTKNOW;
584           }
585           break;
586 
587       // get position in movie
588       case DEMUXER_CTRL_GET_PERCENT_POS:
589           if (mng_priv->header_processed && mng_priv->total_time_ms > 0) {
590               *(int *)arg = (100 * mng_priv->show_cur_time_ms
591                              + mng_priv->total_time_ms / 2)
592                             / mng_priv->total_time_ms;
593               return DEMUXER_CTRL_OK;
594           } else {
595               return DEMUXER_CTRL_DONTKNOW;
596           }
597           break;
598 
599       default:
600           return DEMUXER_CTRL_NOTIMPL;
601 
602     } // switch (cmd)
603 }
604 
605 const demuxer_desc_t demuxer_desc_mng = {
606     "MNG demuxer",
607     "mng",
608     "MNG",
609     "Stefan Schuermans <stefan@blinkenarea.org>",
610     "MNG files, using libmng",
611     DEMUXER_TYPE_MNG,
612     0, // unsafe autodetect (only checking magic at beginning of stream)
613     demux_mng_check_file,
614     demux_mng_fill_buffer,
615     demux_mng_open,
616     demux_mng_close,
617     demux_mng_seek,
618     demux_mng_control
619 };
620