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