c9d685491aaa224e41e97b2dce33fcd743962dd8
[glsdk/omapdrmtest.git] / viddec3test.c
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         struct buffer *lastOutBuf;
64         int outBufsInUseFlag;
65 };
68 struct decoder *decoders[8] = {};
69 int ndecoders = 0;
71 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
72 static int no_process = 0;
73 static int inloop = 0;
75 /* When true, loop at end of playback. */
76 static int loop = 0;
78 static void
79 usage(char *name)
80 {
81         MSG("Usage: %s [OPTIONS] INFILE", name);
82         MSG("Test of viddec3 decoder.");
83         MSG("");
84         MSG("viddec3test options:");
85         MSG("\t-h, --help: Print this help and exit.");
86         MSG("\t--loop\tRestart playback at end of stream.");
87         MSG("\t--inloop\tRestart playback at end of stream along with decoder reinitialization.");
88         MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
89         MSG("");
90         disp_usage();
91 }
93 static void
94 decoder_close(struct decoder *decoder)
95 {
96         if(!decoder) return;
97         /* free output buffers allocated by display */
98         if(inloop < 2 && decoder->disp) disp_free_buffers(decoder->disp,decoder->num_outBuf);
100         if (decoder->status)         dce_free(decoder->status);
101         if (decoder->params)         dce_free(decoder->params);
102         if (decoder->dynParams)      dce_free(decoder->dynParams);
103         if (decoder->inBufs) {
104                 dce_buf_unlock(1, &(decoder->inBufs->descs[0].buf));
105                 close(decoder->inBufs->descs[0].buf);
106                 dce_free(decoder->inBufs);
107         }
108         if (decoder->outBufs)        dce_free(decoder->outBufs);
109         if (decoder->inArgs)         dce_free(decoder->inArgs);
110         if (decoder->outArgs)        dce_free(decoder->outArgs);
111         if (decoder->codec)          VIDDEC3_delete(decoder->codec);
112         if (decoder->engine)         Engine_close(decoder->engine);
113     if (decoder->input_bo)       omap_bo_del(decoder->input_bo);
114         if (decoder->outBuf_fd)      free(decoder->outBuf_fd);
115         if(inloop < 2) {
116                 if (dev)                             dce_deinit(dev);
117                 if (decoder->demux)          demux_deinit(decoder->demux);
118                 if (decoder->disp)           disp_close(decoder->disp);
119                 if(decoder) {
120                   free(decoder);
121                  }
122         }
125 static struct decoder *
126 decoder_open(int argc, char **argv)
128         static struct decoder *decoder = NULL;
129         char *infile = NULL;
130         int i;
131         static int width, height, padded_width, padded_height;
132         Engine_Error ec;
133         XDAS_Int32 err;
135     if(inloop < 2) {
136                 decoder = calloc(1, sizeof(*decoder));
137                 if (!decoder)
138                         return NULL;
140                 MSG("%p: Opening Display..", decoder);
141                 decoder->disp = disp_open(argc, argv);
142                 if (!decoder->disp)
143                         goto usage;
145             /* loop thru args, find input file.. */
146                 for (i = 1; i < argc; i++) {
147                         int fd;
148                             if (!argv[i]) {
149                                     continue;
150                         }
151                         fd = open(argv[i], 0);
152                         if (fd > 0) {
153                                 infile = argv[i];
154                                 argv[i] = NULL;
155                                 close(fd);
156                                 break;
157                         }
158                         break;
159                 }
160                 if (check_args(argc, argv) || !infile)
161                         goto usage;
162                 MSG("%p: Opening Demuxer..", decoder);
163                 decoder->demux = demux_init(infile, &width, &height);
164                 if (!decoder->demux) {
165                         ERROR("%p: could not open demuxer", decoder);
166                         goto fail;
167                 }
168                 MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
170                 /* calculate output buffer parameters: */
171                 width  = ALIGN2 (width, 4);        /* round up to macroblocks */
172                 height = ALIGN2 (height, 4);       /* round up to macroblocks */
173                 if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
174                         padded_width = width;
175                         padded_height= height;
176                 } else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
177                         padded_width  = ALIGN2 (width + PADX, 7);
178                         padded_height = height + PADY_MPEG4;
179                 } else {
180                         padded_width  = ALIGN2 (width + (2*PADX), 7);
181                         padded_height = height + 4*PADY;
182                 }
183                 decoder->num_outBuf   = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
184                 decoder->padded_width = padded_width;
185                 decoder->padded_height = padded_height;
186                 MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
187                         decoder, padded_width, padded_height, decoder->num_outBuf);
188                 dce_set_fd(decoder->disp->fd);
189                 dev = dce_init();
190                 if(dev == NULL) {
191                         ERROR("%p: dce init failed", dev);
192                         goto fail;
193                 }
194                 decoder->framebuf = disp_get_fb(decoder->disp);
195                 if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
196                                 FOURCC_STR("NV12"), decoder->padded_width, decoder->padded_height)) {
197                         ERROR("%p: could not allocate buffers", decoder);
198                         goto fail;
199                 }
200                 if(inloop) inloop = 2; /*Don't bother about looping if not asked to*/
201     }
203         if (!decoder->disp->multiplanar) {
204                 decoder->uv_offset = padded_width * padded_height;
205                 decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
206                 MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
207         }
208         else{
209                 decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
210         }
212         decoder->input_sz = width * height;
213         decoder->input_bo = omap_bo_new(decoder->disp->dev,
214                         decoder->input_sz, OMAP_BO_WC);
215         decoder->input = omap_bo_map(decoder->input_bo);
219         MSG("%p: Opening Engine..", decoder);
220         decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
221         if (!decoder->engine) {
222                 ERROR("%p: could not open engine", decoder);
223                 goto fail;
224         }
226         decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
227         decoder->params->size = sizeof(IVIDDEC3_Params);
229         decoder->params->maxWidth         = width;
230         decoder->params->maxHeight        = height;
231         decoder->params->maxFrameRate     = 30000;
232         decoder->params->maxBitRate       = 10000000;
233         decoder->params->dataEndianness   = XDM_BYTE;
234         decoder->params->forceChromaFormat= XDM_YUV_420SP;
235         decoder->params->operatingMode    = IVIDEO_DECODE_ONLY;
236         decoder->params->displayDelay     = IVIDDEC3_DISPLAY_DELAY_AUTO;
237         decoder->params->displayBufsMode  = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
238         MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
239         decoder->params->inputDataMode    = IVIDEO_ENTIREFRAME;
240         decoder->params->metadataType[0]  = IVIDEO_METADATAPLANE_NONE;
241         decoder->params->metadataType[1]  = IVIDEO_METADATAPLANE_NONE;
242         decoder->params->metadataType[2]  = IVIDEO_METADATAPLANE_NONE;
243         decoder->params->numInputDataUnits= 0;
244         decoder->params->outputDataMode   = IVIDEO_ENTIREFRAME;
245         decoder->params->numOutputDataUnits = 0;
246         decoder->params->errorInfoMode    = IVIDEO_ERRORINFO_OFF;
248         if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
249             decoder->codec = VIDDEC3_create(decoder->engine,
250                                         "ivahd_mpeg2vdec", decoder->params);
251         }
252         else if (decoder->demux->cc->codec_id == AV_CODEC_ID_H264) {
253             decoder->codec = VIDDEC3_create(decoder->engine,
254                                         "ivahd_h264dec", decoder->params);
255         }
256         else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
257                 decoder->demux->first_in_buff = 1;
258                 decoder->codec = VIDDEC3_create(decoder->engine,
259                                         "ivahd_mpeg4dec", decoder->params);
260         }
262         if (!decoder->codec) {
263                 ERROR("%p: could not create codec", decoder);
264                 goto fail;
265         }
267         decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
268         decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
270         decoder->dynParams->decodeHeader  = XDM_DECODE_AU;
272         /*Not Supported: Set default*/
273         decoder->dynParams->displayWidth  = 0;
274         decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
275         decoder->dynParams->newFrameFlag  = XDAS_TRUE;
277         decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
278         decoder->status->size = sizeof(IVIDDEC3_Status);
280         err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
281                         decoder->dynParams, decoder->status);
282         if (err) {
283                 ERROR("%p: fail: %d", decoder, err);
284                 goto fail;
285         }
287         /* not entirely sure why we need to call this here.. just copying omx.. */
288         err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
289                         decoder->dynParams, decoder->status);
290         if (err) {
291                 ERROR("%p: fail: %d", decoder, err);
292                 goto fail;
293         }
295         decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
296         decoder->inBufs->numBufs = 1;
297         decoder->inBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
298         dce_buf_lock(1, &(decoder->inBufs->descs[0].buf));
299         decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
300         decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
303         decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
304         decoder->outBufs->numBufs = 2;
305         decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
306         decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
308         decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
309         decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
311         decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
312         decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
314         decoder->outBufsInUseFlag = XDAS_FALSE;
316         decoder->tdisp = mark(NULL);
318         return decoder;
320 usage:
321         usage(argv[0]);
322 fail:
323         if(inloop) inloop = 1; /*Error case: delete everything*/
324         if (decoder)
325                 decoder_close(decoder);
326         return NULL;
329 static int
330 decoder_process(struct decoder *decoder)
332         XDM2_BufDesc *inBufs = decoder->inBufs;
333         XDM2_BufDesc *outBufs = decoder->outBufs;
334         VIDDEC3_InArgs *inArgs = decoder->inArgs;
335         VIDDEC3_OutArgs *outArgs = decoder->outArgs;
336         struct buffer *buf;
337         int freeBufCount =0;
338         int i, n;
339         XDAS_Int32 err;
340         int eof = 0; /* end of file flag */
342         /* demux; in loop mode, we can do two tries at the end of the stream. */
343         for (i = 0; i < 2; i++) {
344                 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
345                 if (n) {
346                         if(decoder->outBufsInUseFlag == XDAS_FALSE){
347                                 buf = disp_get_vid_buffer(decoder->disp);
348                                 if (!buf) {
349                                         ERROR("%p: fail: out of buffers", decoder);
350                                         return -1;
351                                 }
352                                 decoder->lastOutBuf = buf;
353                         }
354                         else{
355                                 /*For second field decoding, send last output buffer
356                                   decoder uses buffer which was sent for first field
357                                   decoding. No need to pass the buffer. This decision is
358                                   taken based on outArgs->outBufsInUseFlag
359                                  */
360                                 buf = decoder->lastOutBuf;
361                         }
362                         inBufs->descs[0].bufSize.bytes = n;
363                         inArgs->numBytes = n;
364                         DBG("%p: push: %d bytes (%p)", decoder, n, buf);
365                 } else {
366                         /* end of input.. do we need to flush? */
367                         MSG("%p: end of input", decoder);
369                         /* In loop mode: rewind and retry once. */
370                         if (loop && i == 0) {
371                                 int err = demux_rewind(decoder->demux);
372                                 if (err < 0) {
373                                         ERROR("%p: demux_rewind returned error: %d", decoder, err);
374                                         return -1;
375                                 }
376                                 MSG("%p: rewound.", decoder);
377                                 if(!inloop) continue;
378                         }
379                         eof = 1; /* set the flag for end of file to 1 */
380                         /* Control call call with XDM_FLUSH command */
381                         err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
382                                         decoder->dynParams, decoder->status);
383                         inBufs->numBufs = 0;
384                         outBufs->numBufs = 0;
385                         inArgs->inputID = 0;
386                 }
387                 break;
388         }
390         /*set the parameters if it is not the end of file */
391         if (!eof) {
392                 inArgs->inputID = (XDAS_Int32)buf;
393                 outBufs->descs[0].buf = buf->fd[0];
394                 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
396                 if(decoder->outBufsInUseFlag == XDAS_FALSE){
397                         if(buf->multiplanar){
398                                 decoder->outBuf_fd[0] = buf->fd[0];
399                                 decoder->outBuf_fd[1] = buf->fd[1];
400                                 dce_buf_lock(2,decoder->outBuf_fd);
401                         }
402                         else{
403                                 decoder->outBuf_fd[0] = buf->fd[0];
404                                 dce_buf_lock(1,decoder->outBuf_fd);
405                         }
406                         decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
407                         decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
408                 }
409         }
411         do {
412                 if (no_process) {
413                         /* Do not process. This is for benchmarking. We need to "fake"
414                          * the outArgs. */
415                         outArgs->outputID[0] = 0;
416                         outArgs->freeBufID[0] = 0;
417                         if(!eof) {
418                                 outArgs->outputID[0] = buf;
419                                 outArgs->freeBufID[0] = buf;
420                         }
421                         outArgs->outputID[1] = NULL;
422                         outArgs->freeBufID[1] = NULL;
423                         outArgs->outBufsInUseFlag = 0;
425                 } else {
426                         suseconds_t tproc;
427                         tproc = mark(NULL);
428                         err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
429                         DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
430                         if (err) {
431                                 ERROR("%p: process returned error: %d", decoder, err);
432                                 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
433                                 if (XDM_ISFATALERROR(outArgs->extendedError) || ( err == DCE_EXDM_UNSUPPORTED ) || ( err == DCE_EIPC_CALL_FAIL ) || ( err == DCE_EINVALID_INPUT ))
434                                         return -1;
435                         }
436                 }
438                 for (i = 0; outArgs->outputID[i]; i++) {
439                         /* calculate offset to region of interest */
440                         XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
442                         /* get the output buffer and write it to file */
443                         buf = (struct buffer *)outArgs->outputID[i];
444                         if(!no_process)
445                                disp_post_vid_buffer(decoder->disp, buf,
446                                         r->topLeft.x, r->topLeft.y,
447                                         r->bottomRight.x - r->topLeft.x,
448                                         r->bottomRight.y - r->topLeft.y);
449                 }
451                 for (i = 0; outArgs->freeBufID[i]; i++) {
452                         buf = (struct buffer *)outArgs->freeBufID[i];
453                         disp_put_vid_buffer(decoder->disp, buf);
455                         if(buf->multiplanar){
456                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
457                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
458                         }
459                         else{
460                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
461                                 DBG("FreeBufID: %p fd:%d\n", outArgs->freeBufID[i], buf->fd[0]);
462                         }
463                 }
465                 if(freeBufCount){
466             if(!eof)dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
467                         freeBufCount =0;
468                 }
470                 decoder->outBufsInUseFlag = outArgs->outBufsInUseFlag;
472         } while ((err == 0) && eof && !no_process);
474         return (inBufs->numBufs > 0) ? 0 : -1;
477 /* Returns 1 (true) if the mutex is unlocked, which is the
478  * thread's signal to terminate.
479   */
481 pthread_mutex_t mtx;
483 int needQuit()
484  {
485    switch(pthread_mutex_trylock(&mtx)) {
486     case 0: /* if we got the lock, unlock and return 1 (true) */
487               pthread_mutex_unlock(&mtx);
488           return 1;
489     case EBUSY: /* return 0 (false) if the mutex was locked */
490               return 0;
491    }
492   return 1;
493   }
495 void *decode_stream(void *decoderHandle)
497         int ret = 0;
498         struct decoder *decoder = (struct decoder*)decoderHandle;
499     int n = 0;
500     if(!decoder) goto exit;
502     while((ret = decoder_process(decoder)) == 0) {
503            if(needQuit()){
504               inloop = 1;
505               break;
506             }
507          }
508     if((ret != -1 && ret != 0) && inloop) inloop = 1; /*Assuming Good case. Otherwise logic gets messy*/
509     int i = decoder->id;
510         decoder_close(decoder);
511         decoders[i]=NULL;
512 exit:
513         return NULL;
517 static void sig_handler(int signo)
519   if (signo == SIGINT) {
520           int i=0;
521           pthread_mutex_unlock(&mtx);
522           sleep(1);
523           exit(0);
524   }
528 int
529 main(int argc, char **argv)
532    int i, first = 0;
534    struct sigaction sa;
536    sa.sa_handler = sig_handler;
537    sigemptyset(&sa.sa_mask);
538    sa.sa_flags = 0;
540    if (sigaction(SIGINT, &sa, NULL) == -1) {
541      ERROR ("\nDid not catch  SIGINT\n");
542    }
543    signal(SIGINT,sig_handler);
545    pthread_mutex_init(&mtx,NULL);
546    pthread_mutex_lock(&mtx);
548     for (i = 1; i < argc; i++) {
549                 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
550                         usage(argv[0]);
551                         exit(0);
553                 } else if (!strcmp(argv[i], "--loop")) {
554                         loop = 1;
555                         argv[i] = NULL;
557                 } else if (!strcmp(argv[i], "--no-process")) {
558                         no_process = 1;
559                         argv[i] = NULL;
561                 } else if (!strcmp(argv[i], "--inloop")) {
562                         inloop = 1; // this means inloop is detected
563                         DBG("detected inloop = %d\n", inloop);
564                         loop = 1; //we want rewind as well
565                         argv[i] = NULL;
566                 } else if (!strcmp(argv[i], "--")) {
567                         argv[first] = argv[0];
568                         decoders[ndecoders] = decoder_open(i - first, &argv[first]);
569                         decoders[ndecoders]->id = ndecoders;
570                         ndecoders++;
571                         first = i;
572                 }
573         }
575         argv[first] = argv[0];
576         argc = i - first;
578         if(ndecoders) {
579             decoders[ndecoders] = decoder_open(argc ,&argv[first]);
580                 decoders[ndecoders]->id = ndecoders;
581                 ndecoders++;
582         }
584         if (ndecoders > 1) {
585                 pthread_t threadIds[8];
587                 for (i = 0; i < ndecoders; i++) {
588                         if (decoders[i]) {
589                                 int ret = pthread_create(&threadIds[i], NULL,
590                                                 &decode_stream, decoders[i]);
591                                 if (ret != 0)
592                                         ERROR("%p: creation of pthread, error: %d",
593                                                         decoders[i], ret);
594                         }
595                 }
597                 for (i = 0; i < ndecoders; i++) {
598                         pthread_join(threadIds[i], NULL);
599                 }
600         }
601         else {
602                 int itr = 0;
603                 do {
604                         decoders[0] = decoder_open(argc, &argv[first]);
605                         decoders[0]->id = 0;
606                         ndecoders++;
607                         decode_stream(decoders[0]);
608                         if (inloop) {
609                                 MSG("=================Iteration %d complete =============== %d\n", ++itr);
610                         }
611                 }while(inloop);
612         }
614         return 0;