1 /*
2 * Copyright (C) 2012 Texas Instruments
3 * Author: Rob Clark <rob.clark@linaro.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <libdce.h>
21 #include <xf86drm.h>
22 #include <omap_drm.h>
23 #include <omap_drmif.h>
25 #include <pthread.h>
27 #include "util.h"
28 #include "demux.h"
30 /* Padding for width as per Codec Requirement (for h264) */
31 #define PADX 32
32 /* Padding for height as per Codec requirement (for h264)*/
33 #define PADY 24
34 /* omap drm device handle */
35 struct omap_device *dev = NULL;
37 struct decoder {
38 struct display *disp;
39 struct demux *demux;
40 struct buffer *framebuf;
41 Engine_Handle engine;
42 VIDDEC3_Handle codec;
43 VIDDEC3_Params *params;
44 VIDDEC3_DynamicParams *dynParams;
45 VIDDEC3_Status *status;
46 XDM2_BufDesc *inBufs;
47 XDM2_BufDesc *outBufs;
48 VIDDEC3_InArgs *inArgs;
49 VIDDEC3_OutArgs *outArgs;
50 char *input;
51 struct omap_bo *input_bo;
52 int input_sz, uv_offset;
53 int padded_width;
54 int padded_height;
55 int num_outBuf;
56 size_t *outBuf_fd;
57 suseconds_t tdisp;
58 };
60 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
61 static int no_process = 0;
62 static int inloop = 0;
64 /* When true, loop at end of playback. */
65 static int loop = 0;
67 static void
68 usage(char *name)
69 {
70 MSG("Usage: %s [OPTIONS] INFILE", name);
71 MSG("Test of viddec3 decoder.");
72 MSG("");
73 MSG("viddec3test options:");
74 MSG("\t-h, --help: Print this help and exit.");
75 MSG("\t--loop\tRestart playback at end of stream.");
76 MSG("\t--inloop\tRestart playback at end of stream along with decoder reinitialization.");
77 MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
78 MSG("");
79 disp_usage();
80 }
82 static void
83 decoder_close(struct decoder *decoder)
84 {
85 if(!decoder) return;
86 /* free output buffers allocated by display */
87 if(inloop < 2 && decoder->disp) disp_free_buffers(decoder->disp,decoder->num_outBuf);
89 if (decoder->status) dce_free(decoder->status);
90 if (decoder->params) dce_free(decoder->params);
91 if (decoder->dynParams) dce_free(decoder->dynParams);
92 if (decoder->inBufs) {
93 dce_buf_unlock(1, &(decoder->inBufs->descs[0].buf));
94 close(decoder->inBufs->descs[0].buf);
95 dce_free(decoder->inBufs);
96 }
97 if (decoder->outBufs) dce_free(decoder->outBufs);
98 if (decoder->inArgs) dce_free(decoder->inArgs);
99 if (decoder->outArgs) dce_free(decoder->outArgs);
100 if (decoder->codec) VIDDEC3_delete(decoder->codec);
101 if (decoder->engine) Engine_close(decoder->engine);
102 if (decoder->input_bo) omap_bo_del(decoder->input_bo);
103 if (decoder->outBuf_fd) free(decoder->outBuf_fd);
104 if(inloop < 2) {
105 if (dev) dce_deinit(dev);
106 if (decoder->demux) demux_deinit(decoder->demux);
107 if (decoder->disp) disp_close(decoder->disp);
108 if(decoder) free(decoder);
109 }
110 }
112 static struct decoder *
113 decoder_open(int argc, char **argv)
114 {
115 static struct decoder *decoder = NULL;
116 char *infile = NULL;
117 int i;
118 static int width, height, padded_width, padded_height;
119 Engine_Error ec;
120 XDAS_Int32 err;
122 if(inloop < 2) {
123 decoder = calloc(1, sizeof(*decoder));
124 if (!decoder)
125 return NULL;
127 MSG("%p: Opening Display..", decoder);
128 decoder->disp = disp_open(argc, argv);
129 if (!decoder->disp)
130 goto usage;
132 /* loop thru args, find input file.. */
133 for (i = 1; i < argc; i++) {
134 int fd;
135 if (!argv[i]) {
136 continue;
137 }
138 fd = open(argv[i], 0);
139 if (fd > 0) {
140 infile = argv[i];
141 argv[i] = NULL;
142 close(fd);
143 break;
144 }
145 break;
146 }
147 if (check_args(argc, argv) || !infile)
148 goto usage;
149 MSG("%p: Opening Demuxer..", decoder);
150 decoder->demux = demux_init(infile, &width, &height);
151 if (!decoder->demux) {
152 ERROR("%p: could not open demuxer", decoder);
153 goto fail;
154 }
155 MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
157 /* calculate output buffer parameters: */
158 width = ALIGN2 (width, 4); /* round up to macroblocks */
159 height = ALIGN2 (height, 4); /* round up to macroblocks */
160 if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
161 padded_width = width;
162 padded_height= height;
163 }
164 else {
165 padded_width = ALIGN2 (width + (2*PADX), 7);
166 padded_height = height + 4*PADY;
167 }
168 decoder->num_outBuf = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
169 decoder->padded_width = padded_width;
170 decoder->padded_height = padded_height;
171 MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
172 decoder, padded_width, padded_height, decoder->num_outBuf);
173 dce_set_fd(decoder->disp->fd);
174 dev = dce_init();
175 if(dev == NULL) {
176 ERROR("%p: dce init failed", dev);
177 goto fail;
178 }
179 decoder->framebuf = disp_get_fb(decoder->disp);
180 if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
181 FOURCC_STR("NV12"), decoder->padded_width, decoder->padded_height)) {
182 ERROR("%p: could not allocate buffers", decoder);
183 goto fail;
184 }
185 if(inloop) inloop = 2; /*Don't bother about looping if not asked to*/
186 }
188 if (!decoder->disp->multiplanar) {
189 decoder->uv_offset = padded_width * padded_height;
190 decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
191 MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
192 }
193 else{
194 decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
195 }
197 decoder->input_sz = width * height;
198 decoder->input_bo = omap_bo_new(decoder->disp->dev,
199 decoder->input_sz, OMAP_BO_WC);
200 decoder->input = omap_bo_map(decoder->input_bo);
204 MSG("%p: Opening Engine..", decoder);
205 decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
206 if (!decoder->engine) {
207 ERROR("%p: could not open engine", decoder);
208 goto fail;
209 }
211 decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
212 decoder->params->size = sizeof(IVIDDEC3_Params);
214 decoder->params->maxWidth = width;
215 decoder->params->maxHeight = height;
216 decoder->params->maxFrameRate = 30000;
217 decoder->params->maxBitRate = 10000000;
218 decoder->params->dataEndianness = XDM_BYTE;
219 decoder->params->forceChromaFormat= XDM_YUV_420SP;
220 decoder->params->operatingMode = IVIDEO_DECODE_ONLY;
221 decoder->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
222 decoder->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
223 MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
224 decoder->params->inputDataMode = IVIDEO_ENTIREFRAME;
225 decoder->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
226 decoder->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
227 decoder->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
228 decoder->params->numInputDataUnits= 0;
229 decoder->params->outputDataMode = IVIDEO_ENTIREFRAME;
230 decoder->params->numOutputDataUnits = 0;
231 decoder->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
233 if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
234 decoder->codec = VIDDEC3_create(decoder->engine,
235 "ivahd_mpeg2vdec", decoder->params);
236 }
237 else if (decoder->demux->cc->codec_id == AV_CODEC_ID_H264) {
238 decoder->codec = VIDDEC3_create(decoder->engine,
239 "ivahd_h264dec", decoder->params);
240 }
241 else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
242 decoder->demux->first_in_buff = 1;
243 decoder->codec = VIDDEC3_create(decoder->engine,
244 "ivahd_mpeg4dec", decoder->params);
245 }
247 if (!decoder->codec) {
248 ERROR("%p: could not create codec", decoder);
249 goto fail;
250 }
252 decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
253 decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
255 decoder->dynParams->decodeHeader = XDM_DECODE_AU;
257 /*Not Supported: Set default*/
258 decoder->dynParams->displayWidth = 0;
259 decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
260 decoder->dynParams->newFrameFlag = XDAS_TRUE;
262 decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
263 decoder->status->size = sizeof(IVIDDEC3_Status);
265 err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
266 decoder->dynParams, decoder->status);
267 if (err) {
268 ERROR("%p: fail: %d", decoder, err);
269 goto fail;
270 }
272 /* not entirely sure why we need to call this here.. just copying omx.. */
273 err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
274 decoder->dynParams, decoder->status);
275 if (err) {
276 ERROR("%p: fail: %d", decoder, err);
277 goto fail;
278 }
280 decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
281 decoder->inBufs->numBufs = 1;
282 decoder->inBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
283 dce_buf_lock(1, &(decoder->inBufs->descs[0].buf));
284 decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
285 decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
288 decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
289 decoder->outBufs->numBufs = 2;
290 decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
291 decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
293 decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
294 decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
296 decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
297 decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
299 decoder->tdisp = mark(NULL);
301 return decoder;
303 usage:
304 usage(argv[0]);
305 fail:
306 if(inloop) inloop = 1; /*Error case: delete everything*/
307 if (decoder)
308 decoder_close(decoder);
309 return NULL;
310 }
312 static int
313 decoder_process(struct decoder *decoder)
314 {
315 XDM2_BufDesc *inBufs = decoder->inBufs;
316 XDM2_BufDesc *outBufs = decoder->outBufs;
317 VIDDEC3_InArgs *inArgs = decoder->inArgs;
318 VIDDEC3_OutArgs *outArgs = decoder->outArgs;
319 struct buffer *buf;
320 int freeBufCount =0;
321 int i, n;
322 XDAS_Int32 err;
323 int eof = 0; /* end of file flag */
325 /* demux; in loop mode, we can do two tries at the end of the stream. */
326 for (i = 0; i < 2; i++) {
327 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
328 if (n) {
329 buf = disp_get_vid_buffer(decoder->disp);
330 if (!buf) {
331 ERROR("%p: fail: out of buffers", decoder);
332 return -1;
333 }
334 inBufs->descs[0].bufSize.bytes = n;
335 inArgs->numBytes = n;
336 DBG("%p: push: %d bytes (%p)", decoder, n, buf);
337 } else {
338 /* end of input.. do we need to flush? */
339 MSG("%p: end of input", decoder);
341 /* In loop mode: rewind and retry once. */
342 if (loop && i == 0) {
343 int err = demux_rewind(decoder->demux);
344 if (err < 0) {
345 ERROR("%p: demux_rewind returned error: %d", decoder, err);
346 return -1;
347 }
348 MSG("%p: rewound.", decoder);
349 if(!inloop) continue;
350 }
351 eof = 1; /* set the flag for end of file to 1 */
352 /* Control call call with XDM_FLUSH command */
353 err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
354 decoder->dynParams, decoder->status);
355 inBufs->numBufs = 0;
356 outBufs->numBufs = 0;
357 inArgs->inputID = 0;
358 }
359 break;
360 }
362 /*set the parameters if it is not the end of file */
363 if (!eof) {
364 inArgs->inputID = (XDAS_Int32)buf;
365 outBufs->descs[0].buf = buf->fd[0];
366 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
369 if(buf->multiplanar){
370 decoder->outBuf_fd[0] = buf->fd[0];
371 decoder->outBuf_fd[1] = buf->fd[1];
372 dce_buf_lock(2,decoder->outBuf_fd);
373 }
374 else{
375 decoder->outBuf_fd[0] = buf->fd[0];
376 dce_buf_lock(1,decoder->outBuf_fd);
377 }
378 decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
379 decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
380 }
382 do {
383 if (no_process) {
384 /* Do not process. This is for benchmarking. We need to "fake"
385 * the outArgs. */
386 outArgs->outputID[0] = 0;
387 outArgs->freeBufID[0] = 0;
388 if(!eof) {
389 outArgs->outputID[0] = buf;
390 outArgs->freeBufID[0] = buf;
391 }
392 outArgs->outputID[1] = NULL;
393 outArgs->freeBufID[1] = NULL;
394 outArgs->outBufsInUseFlag = 0;
396 } else {
397 suseconds_t tproc;
398 tproc = mark(NULL);
399 err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
400 DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
401 if (err) {
402 ERROR("%p: process returned error: %d", decoder, err);
403 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
404 if (XDM_ISFATALERROR(outArgs->extendedError) || ( err == DCE_EXDM_UNSUPPORTED ) || ( err == DCE_EIPC_CALL_FAIL ) || ( err == DCE_EINVALID_INPUT ))
405 return -1;
406 }
407 }
409 for (i = 0; outArgs->outputID[i]; i++) {
410 /* calculate offset to region of interest */
411 XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
413 /* get the output buffer and write it to file */
414 buf = (struct buffer *)outArgs->outputID[i];
415 if(!no_process)
416 disp_post_vid_buffer(decoder->disp, buf,
417 r->topLeft.x, r->topLeft.y,
418 r->bottomRight.x - r->topLeft.x,
419 r->bottomRight.y - r->topLeft.y);
420 }
422 for (i = 0; outArgs->freeBufID[i]; i++) {
423 buf = (struct buffer *)outArgs->freeBufID[i];
424 disp_put_vid_buffer(decoder->disp, buf);
426 if(buf->multiplanar){
427 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
428 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
429 }
430 else{
431 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
432 DBG("FreeBufID: %p fd:%d\n", outArgs->freeBufID[i], buf->fd[0]);
433 }
434 }
436 if(freeBufCount){
437 if(!eof)dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
438 freeBufCount =0;
439 }
440 if (outArgs->outBufsInUseFlag) {
441 MSG("%p: TODO... outBufsInUseFlag", decoder); // XXX
442 }
443 } while ((err == 0) && eof && !no_process);
445 return (inBufs->numBufs > 0) ? 0 : -1;
446 }
448 void *decode_stream(void *decoderHandle)
449 {
450 int ret = 0;
451 struct decoder *decoder = (struct decoder*)decoderHandle;
452 int n = 0;
453 if(!decoder) goto exit;
455 while((ret = decoder_process(decoder)) == 0);
456 if((ret != -1 && ret != 0) && inloop) inloop = 1; /*Assuming Good case. Otherwise logic gets messy*/
457 decoder_close(decoder);
458 exit:
459 return NULL;
460 }
462 int
463 main(int argc, char **argv)
464 {
465 struct decoder *decoders[8] = {};
466 int i, first = 0, ndecoders = 0;
468 for (i = 1; i < argc; i++) {
469 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
470 usage(argv[0]);
471 exit(0);
473 } else if (!strcmp(argv[i], "--loop")) {
474 loop = 1;
475 argv[i] = NULL;
477 } else if (!strcmp(argv[i], "--no-process")) {
478 no_process = 1;
479 argv[i] = NULL;
481 } else if (!strcmp(argv[i], "--inloop")) {
482 inloop = 1; // this means inloop is detected
483 DBG("detected inloop = %d\n", inloop);
484 loop = 1; //we want rewind as well
485 argv[i] = NULL;
486 } else if (!strcmp(argv[i], "--")) {
487 argv[first] = argv[0];
488 decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
489 first = i;
490 }
491 }
493 argv[first] = argv[0];
494 argc = i - first;
496 if(ndecoders) decoders[ndecoders++] = decoder_open(argc ,&argv[first]);
498 if (ndecoders > 1) {
499 pthread_t threadIds[8];
501 for (i = 0; i < ndecoders; i++) {
502 if (decoders[i]) {
503 int ret = pthread_create(&threadIds[i], NULL,
504 &decode_stream, decoders[i]);
505 if (ret != 0)
506 ERROR("%p: creation of pthread, error: %d",
507 decoders[i], ret);
508 }
509 }
511 for (i = 0; i < ndecoders; i++) {
512 pthread_join(threadIds[i], NULL);
513 }
514 }
515 else {
516 int itr = 0;
517 do {
518 decoders[0] = decoder_open(argc, &argv[first]);
519 decode_stream(decoders[0]);
520 if (inloop) {
521 MSG("=================Iteration %d complete =============== %d\n", ++itr);
522 }
523 }while(inloop);
524 }
526 return 0;
527 }