]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/omapdrmtest.git/blob - viddec3test.c
a187c40e071602f4ef61344d15f475327c9acfb1
[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 };
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         }
123 static struct decoder *
124 decoder_open(int argc, char **argv)
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;
325 static int
326 decoder_process(struct decoder *decoder)
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;
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)
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;
501 static void sig_handler(int signo)
503   if (signo == SIGINT) {
504           int i=0;
505           pthread_mutex_unlock(&mtx);
506           sleep(1);
507           exit(0);
508   }
512 int
513 main(int argc, char **argv)
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;