a187c40e071602f4ef61344d15f475327c9acfb1
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>
24 #include <signal.h>
25 #include <unistd.h>
27 #include <pthread.h>
29 #include "util.h"
30 #include "demux.h"
32 /* Padding for width as per Codec Requirement (for h264) */
33 #define PADX 32
34 /* Padding for height as per Codec requirement (for h264)*/
35 #define PADY 24
36 /* Padding for height as per Codec requirement (for MPEG4)*/
37 #define PADY_MPEG4 32
38 /* omap drm device handle */
39 struct omap_device *dev = NULL;
41 struct decoder {
42 struct display *disp;
43 struct demux *demux;
44 struct buffer *framebuf;
45 Engine_Handle engine;
46 VIDDEC3_Handle codec;
47 VIDDEC3_Params *params;
48 VIDDEC3_DynamicParams *dynParams;
49 VIDDEC3_Status *status;
50 XDM2_BufDesc *inBufs;
51 XDM2_BufDesc *outBufs;
52 VIDDEC3_InArgs *inArgs;
53 VIDDEC3_OutArgs *outArgs;
54 char *input;
55 struct omap_bo *input_bo;
56 int input_sz, uv_offset;
57 int padded_width;
58 int padded_height;
59 int num_outBuf;
60 size_t *outBuf_fd;
61 suseconds_t tdisp;
62 int id;
63 };
66 struct decoder *decoders[8] = {};
67 int ndecoders = 0;
69 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
70 static int no_process = 0;
71 static int inloop = 0;
73 /* When true, loop at end of playback. */
74 static int loop = 0;
76 static void
77 usage(char *name)
78 {
79 MSG("Usage: %s [OPTIONS] INFILE", name);
80 MSG("Test of viddec3 decoder.");
81 MSG("");
82 MSG("viddec3test options:");
83 MSG("\t-h, --help: Print this help and exit.");
84 MSG("\t--loop\tRestart playback at end of stream.");
85 MSG("\t--inloop\tRestart playback at end of stream along with decoder reinitialization.");
86 MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
87 MSG("");
88 disp_usage();
89 }
91 static void
92 decoder_close(struct decoder *decoder)
93 {
94 if(!decoder) return;
95 /* free output buffers allocated by display */
96 if(inloop < 2 && decoder->disp) disp_free_buffers(decoder->disp,decoder->num_outBuf);
98 if (decoder->status) dce_free(decoder->status);
99 if (decoder->params) dce_free(decoder->params);
100 if (decoder->dynParams) dce_free(decoder->dynParams);
101 if (decoder->inBufs) {
102 dce_buf_unlock(1, &(decoder->inBufs->descs[0].buf));
103 close(decoder->inBufs->descs[0].buf);
104 dce_free(decoder->inBufs);
105 }
106 if (decoder->outBufs) dce_free(decoder->outBufs);
107 if (decoder->inArgs) dce_free(decoder->inArgs);
108 if (decoder->outArgs) dce_free(decoder->outArgs);
109 if (decoder->codec) VIDDEC3_delete(decoder->codec);
110 if (decoder->engine) Engine_close(decoder->engine);
111 if (decoder->input_bo) omap_bo_del(decoder->input_bo);
112 if (decoder->outBuf_fd) free(decoder->outBuf_fd);
113 if(inloop < 2) {
114 if (dev) dce_deinit(dev);
115 if (decoder->demux) demux_deinit(decoder->demux);
116 if (decoder->disp) disp_close(decoder->disp);
117 if(decoder) {
118 free(decoder);
119 }
120 }
121 }
123 static struct decoder *
124 decoder_open(int argc, char **argv)
125 {
126 struct decoder *decoder = NULL;
127 char *infile = NULL;
128 int i;
129 int width, height, padded_width, padded_height;
130 Engine_Error ec;
131 XDAS_Int32 err;
133 if(inloop < 2) {
134 decoder = calloc(1, sizeof(*decoder));
135 if (!decoder)
136 return NULL;
138 MSG("%p: Opening Display..", decoder);
139 decoder->disp = disp_open(argc, argv);
140 if (!decoder->disp)
141 goto usage;
143 /* loop thru args, find input file.. */
144 for (i = 1; i < argc; i++) {
145 int fd;
146 if (!argv[i]) {
147 continue;
148 }
149 fd = open(argv[i], 0);
150 if (fd > 0) {
151 infile = argv[i];
152 argv[i] = NULL;
153 close(fd);
154 break;
155 }
156 break;
157 }
158 if (check_args(argc, argv) || !infile)
159 goto usage;
160 MSG("%p: Opening Demuxer..", decoder);
161 decoder->demux = demux_init(infile, &width, &height);
162 if (!decoder->demux) {
163 ERROR("%p: could not open demuxer", decoder);
164 goto fail;
165 }
166 MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
168 /* calculate output buffer parameters: */
169 width = ALIGN2 (width, 4); /* round up to macroblocks */
170 height = ALIGN2 (height, 4); /* round up to macroblocks */
171 if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
172 padded_width = width;
173 padded_height= height;
174 } else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
175 padded_width = ALIGN2 (width + PADX, 7);
176 padded_height = height + PADY_MPEG4;
177 } else {
178 padded_width = ALIGN2 (width + (2*PADX), 7);
179 padded_height = height + 4*PADY;
180 }
181 decoder->num_outBuf = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
182 decoder->padded_width = padded_width;
183 decoder->padded_height = padded_height;
184 MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
185 decoder, padded_width, padded_height, decoder->num_outBuf);
186 dce_set_fd(decoder->disp->fd);
187 dev = dce_init();
188 if(dev == NULL) {
189 ERROR("%p: dce init failed", dev);
190 goto fail;
191 }
192 decoder->framebuf = disp_get_fb(decoder->disp);
193 if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
194 FOURCC_STR("NV12"), decoder->padded_width, decoder->padded_height)) {
195 ERROR("%p: could not allocate buffers", decoder);
196 goto fail;
197 }
198 if(inloop) inloop = 2; /*Don't bother about looping if not asked to*/
199 }
201 if (!decoder->disp->multiplanar) {
202 decoder->uv_offset = padded_width * padded_height;
203 decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
204 MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
205 }
206 else{
207 decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
208 }
210 decoder->input_sz = width * height;
211 decoder->input_bo = omap_bo_new(decoder->disp->dev,
212 decoder->input_sz, OMAP_BO_WC);
213 decoder->input = omap_bo_map(decoder->input_bo);
217 MSG("%p: Opening Engine..", decoder);
218 decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
219 if (!decoder->engine) {
220 ERROR("%p: could not open engine", decoder);
221 goto fail;
222 }
224 decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
225 decoder->params->size = sizeof(IVIDDEC3_Params);
227 decoder->params->maxWidth = width;
228 decoder->params->maxHeight = height;
229 decoder->params->maxFrameRate = 30000;
230 decoder->params->maxBitRate = 10000000;
231 decoder->params->dataEndianness = XDM_BYTE;
232 decoder->params->forceChromaFormat= XDM_YUV_420SP;
233 decoder->params->operatingMode = IVIDEO_DECODE_ONLY;
234 decoder->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
235 decoder->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
236 MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
237 decoder->params->inputDataMode = IVIDEO_ENTIREFRAME;
238 decoder->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
239 decoder->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
240 decoder->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
241 decoder->params->numInputDataUnits= 0;
242 decoder->params->outputDataMode = IVIDEO_ENTIREFRAME;
243 decoder->params->numOutputDataUnits = 0;
244 decoder->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
246 if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
247 decoder->codec = VIDDEC3_create(decoder->engine,
248 "ivahd_mpeg2vdec", decoder->params);
249 }
250 else if (decoder->demux->cc->codec_id == AV_CODEC_ID_H264) {
251 decoder->codec = VIDDEC3_create(decoder->engine,
252 "ivahd_h264dec", decoder->params);
253 }
254 else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
255 decoder->demux->first_in_buff = 1;
256 decoder->codec = VIDDEC3_create(decoder->engine,
257 "ivahd_mpeg4dec", decoder->params);
258 }
260 if (!decoder->codec) {
261 ERROR("%p: could not create codec", decoder);
262 goto fail;
263 }
265 decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
266 decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
268 decoder->dynParams->decodeHeader = XDM_DECODE_AU;
270 /*Not Supported: Set default*/
271 decoder->dynParams->displayWidth = 0;
272 decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
273 decoder->dynParams->newFrameFlag = XDAS_TRUE;
275 decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
276 decoder->status->size = sizeof(IVIDDEC3_Status);
278 err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
279 decoder->dynParams, decoder->status);
280 if (err) {
281 ERROR("%p: fail: %d", decoder, err);
282 goto fail;
283 }
285 /* not entirely sure why we need to call this here.. just copying omx.. */
286 err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
287 decoder->dynParams, decoder->status);
288 if (err) {
289 ERROR("%p: fail: %d", decoder, err);
290 goto fail;
291 }
293 decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
294 decoder->inBufs->numBufs = 1;
295 decoder->inBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
296 dce_buf_lock(1, &(decoder->inBufs->descs[0].buf));
297 decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
298 decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
301 decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
302 decoder->outBufs->numBufs = 2;
303 decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
304 decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
306 decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
307 decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
309 decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
310 decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
312 decoder->tdisp = mark(NULL);
314 return decoder;
316 usage:
317 usage(argv[0]);
318 fail:
319 if(inloop) inloop = 1; /*Error case: delete everything*/
320 if (decoder)
321 decoder_close(decoder);
322 return NULL;
323 }
325 static int
326 decoder_process(struct decoder *decoder)
327 {
328 XDM2_BufDesc *inBufs = decoder->inBufs;
329 XDM2_BufDesc *outBufs = decoder->outBufs;
330 VIDDEC3_InArgs *inArgs = decoder->inArgs;
331 VIDDEC3_OutArgs *outArgs = decoder->outArgs;
332 struct buffer *buf;
333 int freeBufCount =0;
334 int i, n;
335 XDAS_Int32 err;
336 int eof = 0; /* end of file flag */
338 /* demux; in loop mode, we can do two tries at the end of the stream. */
339 for (i = 0; i < 2; i++) {
340 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
341 if (n) {
342 buf = disp_get_vid_buffer(decoder->disp);
343 if (!buf) {
344 ERROR("%p: fail: out of buffers", decoder);
345 return -1;
346 }
347 inBufs->descs[0].bufSize.bytes = n;
348 inArgs->numBytes = n;
349 DBG("%p: push: %d bytes (%p)", decoder, n, buf);
350 } else {
351 /* end of input.. do we need to flush? */
352 MSG("%p: end of input", decoder);
354 /* In loop mode: rewind and retry once. */
355 if (loop && i == 0) {
356 int err = demux_rewind(decoder->demux);
357 if (err < 0) {
358 ERROR("%p: demux_rewind returned error: %d", decoder, err);
359 return -1;
360 }
361 MSG("%p: rewound.", decoder);
362 if(!inloop) continue;
363 }
364 eof = 1; /* set the flag for end of file to 1 */
365 /* Control call call with XDM_FLUSH command */
366 err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
367 decoder->dynParams, decoder->status);
368 inBufs->numBufs = 0;
369 outBufs->numBufs = 0;
370 inArgs->inputID = 0;
371 }
372 break;
373 }
375 /*set the parameters if it is not the end of file */
376 if (!eof) {
377 inArgs->inputID = (XDAS_Int32)buf;
378 outBufs->descs[0].buf = buf->fd[0];
379 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
382 if(buf->multiplanar){
383 decoder->outBuf_fd[0] = buf->fd[0];
384 decoder->outBuf_fd[1] = buf->fd[1];
385 dce_buf_lock(2,decoder->outBuf_fd);
386 }
387 else{
388 decoder->outBuf_fd[0] = buf->fd[0];
389 dce_buf_lock(1,decoder->outBuf_fd);
390 }
391 decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
392 decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
393 }
395 do {
396 if (no_process) {
397 /* Do not process. This is for benchmarking. We need to "fake"
398 * the outArgs. */
399 outArgs->outputID[0] = 0;
400 outArgs->freeBufID[0] = 0;
401 if(!eof) {
402 outArgs->outputID[0] = buf;
403 outArgs->freeBufID[0] = buf;
404 }
405 outArgs->outputID[1] = NULL;
406 outArgs->freeBufID[1] = NULL;
407 outArgs->outBufsInUseFlag = 0;
409 } else {
410 suseconds_t tproc;
411 tproc = mark(NULL);
412 err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
413 DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
414 if (err) {
415 ERROR("%p: process returned error: %d", decoder, err);
416 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
417 if (XDM_ISFATALERROR(outArgs->extendedError) || ( err == DCE_EXDM_UNSUPPORTED ) || ( err == DCE_EIPC_CALL_FAIL ) || ( err == DCE_EINVALID_INPUT ))
418 return -1;
419 }
420 }
422 for (i = 0; outArgs->outputID[i]; i++) {
423 /* calculate offset to region of interest */
424 XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
426 /* get the output buffer and write it to file */
427 buf = (struct buffer *)outArgs->outputID[i];
428 if(!no_process)
429 disp_post_vid_buffer(decoder->disp, buf,
430 r->topLeft.x, r->topLeft.y,
431 r->bottomRight.x - r->topLeft.x,
432 r->bottomRight.y - r->topLeft.y);
433 }
435 for (i = 0; outArgs->freeBufID[i]; i++) {
436 buf = (struct buffer *)outArgs->freeBufID[i];
437 disp_put_vid_buffer(decoder->disp, buf);
439 if(buf->multiplanar){
440 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
441 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
442 }
443 else{
444 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
445 DBG("FreeBufID: %p fd:%d\n", outArgs->freeBufID[i], buf->fd[0]);
446 }
447 }
449 if(freeBufCount){
450 if(!eof)dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
451 freeBufCount =0;
452 }
453 if (outArgs->outBufsInUseFlag) {
454 MSG("%p: TODO... outBufsInUseFlag", decoder); // XXX
455 }
456 } while ((err == 0) && eof && !no_process);
458 return (inBufs->numBufs > 0) ? 0 : -1;
459 }
461 /* Returns 1 (true) if the mutex is unlocked, which is the
462 * thread's signal to terminate.
463 */
465 pthread_mutex_t mtx;
467 int needQuit()
468 {
469 switch(pthread_mutex_trylock(&mtx)) {
470 case 0: /* if we got the lock, unlock and return 1 (true) */
471 pthread_mutex_unlock(&mtx);
472 return 1;
473 case EBUSY: /* return 0 (false) if the mutex was locked */
474 return 0;
475 }
476 return 1;
477 }
479 void *decode_stream(void *decoderHandle)
480 {
481 int ret = 0;
482 struct decoder *decoder = (struct decoder*)decoderHandle;
483 int n = 0;
484 if(!decoder) goto exit;
486 while((ret = decoder_process(decoder)) == 0) {
487 if(needQuit()){
488 inloop = 1;
489 break;
490 }
491 }
492 if((ret != -1 && ret != 0) && inloop) inloop = 1; /*Assuming Good case. Otherwise logic gets messy*/
493 int i = decoder->id;
494 decoder_close(decoder);
495 decoders[i]=NULL;
496 exit:
497 return NULL;
498 }
501 static void sig_handler(int signo)
502 {
503 if (signo == SIGINT) {
504 int i=0;
505 pthread_mutex_unlock(&mtx);
506 sleep(1);
507 exit(0);
508 }
509 }
512 int
513 main(int argc, char **argv)
514 {
516 int i, first = 0;
518 struct sigaction sa;
520 sa.sa_handler = sig_handler;
521 sigemptyset(&sa.sa_mask);
522 sa.sa_flags = 0;
524 if (sigaction(SIGINT, &sa, NULL) == -1) {
525 ERROR ("\nDid not catch SIGINT\n");
526 }
527 signal(SIGINT,sig_handler);
529 pthread_mutex_init(&mtx,NULL);
530 pthread_mutex_lock(&mtx);
532 for (i = 1; i < argc; i++) {
533 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
534 usage(argv[0]);
535 exit(0);
537 } else if (!strcmp(argv[i], "--loop")) {
538 loop = 1;
539 argv[i] = NULL;
541 } else if (!strcmp(argv[i], "--no-process")) {
542 no_process = 1;
543 argv[i] = NULL;
545 } else if (!strcmp(argv[i], "--inloop")) {
546 inloop = 1; // this means inloop is detected
547 DBG("detected inloop = %d\n", inloop);
548 loop = 1; //we want rewind as well
549 argv[i] = NULL;
550 } else if (!strcmp(argv[i], "--")) {
551 argv[first] = argv[0];
552 decoders[ndecoders] = decoder_open(i - first, &argv[first]);
553 decoders[ndecoders]->id = ndecoders;
554 ndecoders++;
555 first = i;
556 }
557 }
559 argv[first] = argv[0];
560 argc = i - first;
562 if(ndecoders) {
563 decoders[ndecoders] = decoder_open(argc ,&argv[first]);
564 decoders[ndecoders]->id = ndecoders;
565 ndecoders++;
566 }
568 if (ndecoders > 1) {
569 pthread_t threadIds[8];
571 for (i = 0; i < ndecoders; i++) {
572 if (decoders[i]) {
573 int ret = pthread_create(&threadIds[i], NULL,
574 &decode_stream, decoders[i]);
575 if (ret != 0)
576 ERROR("%p: creation of pthread, error: %d",
577 decoders[i], ret);
578 }
579 }
581 for (i = 0; i < ndecoders; i++) {
582 pthread_join(threadIds[i], NULL);
583 }
584 }
585 else {
586 int itr = 0;
587 do {
588 decoders[0] = decoder_open(argc, &argv[first]);
589 decoders[0]->id = 0;
590 ndecoders++;
591 decode_stream(decoders[0]);
592 if (inloop) {
593 MSG("=================Iteration %d complete =============== %d\n", ++itr);
594 }
595 }while(inloop);
596 }
598 return 0;
599 }