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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdlib.h>
26 
27 /* #define LOG */
28 #define LOG_MODULE "demux_ivf"
29 #define LOG_VERBOSE
30 
31 #include "group_video.h"
32 
33 #include <xine/xine_internal.h>
34 #include <xine/demux.h>
35 #include "bswap.h"
36 
37 static const struct {
38   uint32_t buf_type;
39   char     fourcc[4];
40 } ivf_tag_map[] = {
41   { BUF_VIDEO_AV1,  "AV01" },
42   { BUF_VIDEO_H264, "H264" },
43   { BUF_VIDEO_HEVC, "HEVC" },
44   { BUF_VIDEO_VP8,  "VP80" },
45   { BUF_VIDEO_VP9,  "VP90" },
46 };
47 
48 typedef struct {
49   demux_plugin_t      demux_plugin;
50 
51   xine_stream_t       *stream;
52   fifo_buffer_t       *video_fifo;
53   input_plugin_t      *input;
54   int                  status;
55   int                  seek_flag;
56   int64_t              last_pts;
57   uint32_t             buf_type;
58 
59   uint32_t             num_frames;
60   uint32_t             frame_number;
61   uint32_t             frame_rate_num, frame_rate_den;
62 } demux_ivf_t;
63 
demux_ivf_send_chunk(demux_plugin_t * this_gen)64 static int demux_ivf_send_chunk(demux_plugin_t *this_gen)
65 {
66   demux_ivf_t *this = (demux_ivf_t *)this_gen;
67   uint8_t  hdr[12];
68   uint32_t len;
69   int64_t  pts;
70   int      normpos = 0;
71   off_t    length;
72   int      input_time, total_time;
73 
74   /* read and parse header */
75 
76   if (this->input->read(this->input, hdr, 12) != 12) {
77     this->status = DEMUX_FINISHED;
78     return this->status;
79   }
80 
81   len = _X_LE_32(hdr);
82   pts = _X_LE_64(hdr + 4);
83 
84   lprintf("frame %d: pts %ld %ld\n", this->frame_number, pts, pts * 90000 * this->frame_rate_num / this->frame_rate_den);
85   pts = pts * 90000 * this->frame_rate_num / this->frame_rate_den;
86 
87   /* handle seek and discontinuity */
88   if (this->seek_flag) {
89     _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK);
90     this->seek_flag = 0;
91   } else if (this->last_pts - pts > 270000 || this->last_pts - pts < -270000) {
92     _x_demux_control_newpts(this->stream, pts, 0);
93   }
94   this->last_pts = pts;
95 
96   /* calculate normpos */
97   length = this->input->get_length(this->input);
98   if (length > 0) {
99     off_t curpos = this->input->get_current_pos(this->input);
100     if (curpos > 0) {
101       normpos = (int)((double) curpos * 65535 / length);
102     }
103   }
104 
105   /* calculate timepos */
106   input_time = (uint64_t)this->frame_number * 1000 * this->frame_rate_num / this->frame_rate_den;
107   total_time = (uint64_t)this->num_frames   * 1000 * this->frame_rate_num / this->frame_rate_den;
108 
109   /* send frame */
110   if (_x_demux_read_send_data(this->video_fifo,
111                               this->input,
112                               len, pts, this->buf_type, 0,
113                               normpos, input_time, total_time,
114                               this->frame_number) < 0) {
115     this->status = DEMUX_FINISHED;
116     return this->status;
117   }
118 
119   this->frame_number++;
120 
121   return this->status;
122 }
123 
demux_ivf_get_status(demux_plugin_t * this_gen)124 static int demux_ivf_get_status(demux_plugin_t *this_gen)
125 {
126   demux_ivf_t *this = (demux_ivf_t *)this_gen;
127   return this->status;
128 }
129 
demux_ivf_send_headers(demux_plugin_t * this_gen)130 static void demux_ivf_send_headers(demux_plugin_t *this_gen)
131 {
132   demux_ivf_t    *this = (demux_ivf_t *)this_gen;
133   buf_element_t  *buf;
134   uint8_t         hdr[32];
135   int             width, height;
136   xine_bmiheader *bih;
137   off_t           file_length;
138 
139   this->video_fifo = this->stream->video_fifo;
140   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
141   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 0);
142   _x_demux_control_start(this->stream);
143 
144   /* read and parse header */
145 
146   if (this->input->seek(this->input, 0, SEEK_SET) != 0) {
147     this->status = DEMUX_FINISHED;
148     return;
149   }
150 
151   if (this->input->read(this->input, hdr, 32) != 32) {
152     this->status = DEMUX_FINISHED;
153     return;
154   }
155 
156   width                = _X_LE_16(&hdr[12]);
157   height               = _X_LE_16(&hdr[14]);
158   this->frame_rate_den = _X_LE_32(&hdr[16]);
159   this->frame_rate_num = _X_LE_32(&hdr[20]);
160   this->num_frames     = _X_LE_32(&hdr[24]);
161 
162   if (!this->frame_rate_num || !this->frame_rate_den) {
163     this->status = DEMUX_FINISHED;
164     return;
165   }
166   xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": "
167           "codec=%4.4s size=%dx%d rate=%u:%u num_frames=%u\n",
168           (const char *)hdr + 8, width, height,
169           this->frame_rate_num, this->frame_rate_den, this->num_frames);
170 
171   _x_stream_info_set (this->stream, XINE_STREAM_INFO_FRAME_DURATION, (int64_t)this->frame_rate_num * 90000 / this->frame_rate_den);
172   file_length = this->input->get_length(this->input);
173   if (file_length > 32 + 12*this->num_frames) {
174     file_length = file_length - 32 - 12*this->num_frames;
175     _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_BITRATE,
176                        file_length / this->frame_rate_num * this->frame_rate_den / this->num_frames * 8);
177   }
178 
179   /* configure decoder */
180 
181   buf = this->video_fifo->buffer_pool_alloc(this->video_fifo);
182 
183   buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_STDHEADER | BUF_FLAG_FRAME_END;
184   buf->type          = this->buf_type;
185 
186   bih = (xine_bmiheader *)buf->content;
187   memset(bih, 0, sizeof(*bih));
188   bih->biSize   = sizeof(xine_bmiheader);
189   bih->biWidth  = width;
190   bih->biHeight = height;
191   buf->size = sizeof(*bih);
192 
193   buf->decoder_flags   |= BUF_FLAG_FRAMERATE;
194   buf->decoder_info[0]  = (int64_t)this->frame_rate_num * 90000 / this->frame_rate_den;
195 
196   buf->decoder_flags   |= BUF_FLAG_ASPECT;
197   buf->decoder_info[1]  = width;
198   buf->decoder_info[2]  = height;
199 
200   this->video_fifo->put(this->video_fifo, buf);
201 
202   this->status = DEMUX_OK;
203 }
204 
demux_ivf_seek(demux_plugin_t * this_gen,off_t start_pos,int start_time,int playing)205 static int demux_ivf_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time, int playing)
206 {
207   demux_ivf_t *this = (demux_ivf_t *)this_gen;
208 
209   this->seek_flag = 1;
210 
211   /* no seek table, only seeking to beginning is supported */
212   if (start_pos == 0 && start_time == 0) {
213 
214     if (playing)
215       _x_demux_flush_engine(this->stream);
216 
217     if (this->input->seek (this->input, 32, SEEK_SET) != 32) {
218       return this->status;
219     }
220 
221     this->frame_number = 0;
222     this->status = DEMUX_OK;
223     return this->status;
224   }
225 
226   return this->status;
227 }
228 
demux_ivf_get_stream_length(demux_plugin_t * this_gen)229 static int demux_ivf_get_stream_length(demux_plugin_t *this_gen)
230 {
231   demux_ivf_t *this = (demux_ivf_t *)this_gen;
232 
233   if (!this->frame_rate_den)
234     return 0;
235 
236   return (uint64_t)this->num_frames * 1000 * this->frame_rate_num / this->frame_rate_den;
237 }
238 
demux_ivf_get_capabilities(demux_plugin_t * this_gen)239 static uint32_t demux_ivf_get_capabilities(demux_plugin_t *this_gen)
240 {
241   (void)this_gen;
242   return DEMUX_CAP_NOCAP;
243 }
244 
demux_ivf_get_optional_data(demux_plugin_t * this_gen,void * data,int data_type)245 static int demux_ivf_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type)
246 {
247   (void)this_gen;
248   (void)data;
249   (void)data_type;
250   return DEMUX_OPTIONAL_UNSUPPORTED;
251 }
252 
open_plugin(demux_class_t * class_gen,xine_stream_t * stream,input_plugin_t * input)253 static demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input)
254 {
255   demux_ivf_t *this;
256   uint8_t      scratch[32];
257   size_t       i;
258   uint32_t     buf_type = 0;
259 
260   switch (stream->content_detection_method) {
261 
262   case METHOD_BY_CONTENT:
263     if (_x_demux_read_header(input, scratch, 32) != 32)
264       return 0;
265     if ( !_x_is_fourcc(scratch, "DKIF") )
266       return 0;
267     if (_X_LE_16(scratch + 4) != 0 /* version */ ||
268         _X_LE_16(scratch + 6) != 32 /* header size */)
269       return 0;
270     if (!_X_LE_32(scratch + 16) /* frame_rate_den */ ||
271         !_X_LE_32(scratch + 20) /* frame_rate_num */ )
272       return 0;
273     for (i = 0; i < sizeof(ivf_tag_map) / sizeof(ivf_tag_map[0]); i++) {
274       if (_x_is_fourcc(&scratch[8], ivf_tag_map[i].fourcc)) {
275         buf_type = ivf_tag_map[i].buf_type;
276         break;
277       }
278     }
279     if (!buf_type) {
280       xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": "
281               "unsupportd codec tag %4.4s\n", &scratch[8]);
282       return 0;
283     }
284     break;
285 
286   case METHOD_BY_MRL:
287   case METHOD_EXPLICIT:
288     break;
289 
290   default:
291     return NULL;
292   }
293 
294   this = calloc(1, sizeof(*this));
295   if (!this)
296     return NULL;
297 
298   this->stream   = stream;
299   this->input    = input;
300   this->status   = DEMUX_FINISHED;
301   this->buf_type = buf_type;
302 
303   this->demux_plugin.send_headers      = demux_ivf_send_headers;
304   this->demux_plugin.send_chunk        = demux_ivf_send_chunk;
305   this->demux_plugin.seek              = demux_ivf_seek;
306   this->demux_plugin.dispose           = default_demux_plugin_dispose;
307   this->demux_plugin.get_status        = demux_ivf_get_status;
308   this->demux_plugin.get_stream_length = demux_ivf_get_stream_length;
309   this->demux_plugin.get_capabilities  = demux_ivf_get_capabilities;
310   this->demux_plugin.get_optional_data = demux_ivf_get_optional_data;
311   this->demux_plugin.demux_class       = class_gen;
312 
313   return &this->demux_plugin;
314 }
315 
demux_ivf_init_class(xine_t * xine,const void * data)316 void *demux_ivf_init_class(xine_t *xine, const void *data)
317 {
318   (void)xine;
319   (void)data;
320 
321   static const demux_class_t demux_ivf_class = {
322     .open_plugin     = open_plugin,
323     .description     = N_("IVF demuxer"),
324     .identifier      = "ivf",
325     .mimetypes       = NULL,
326     .extensions      = "ivf",
327     .dispose         = NULL,
328   };
329 
330   return (void *)&demux_ivf_class;
331 }
332 
333