viddec3test: dce_buf_lock & unlock of OutBuf_fd
[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;
354                                 inArgs->inputID = (XDAS_Int32)buf;
355                                 outBufs->descs[0].buf = buf->fd[0];
356                                 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
358                                 if(buf->multiplanar){
359                                     decoder->outBuf_fd[0] = buf->fd[0];
360                                     decoder->outBuf_fd[1] = buf->fd[1];
361                                     dce_buf_lock(2,decoder->outBuf_fd);
362                                 }
363                                 else{
364                                     decoder->outBuf_fd[0] = buf->fd[0];
365                                     dce_buf_lock(1,decoder->outBuf_fd);
366                                 }
367                                 decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
368                                 decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
369                         }
370                         else{
371                                 /*For second field decoding, send last output buffer
372                                   decoder uses buffer which was sent for first field
373                                   decoding. No need to pass the buffer. This decision is
374                                   taken based on outArgs->outBufsInUseFlag
375                                  */
376                                 buf = decoder->lastOutBuf;
377                         }
378                         inBufs->descs[0].bufSize.bytes = n;
379                         inArgs->numBytes = n;
380                         DBG("%p: push: %d bytes (%p)", decoder, n, buf);
381                 } else {
382                         /* end of input.. do we need to flush? */
383                         MSG("%p: end of input", decoder);
385                         /* In loop mode: rewind and retry once. */
386                         if (loop && i == 0) {
387                                 int err = demux_rewind(decoder->demux);
388                                 if (err < 0) {
389                                         ERROR("%p: demux_rewind returned error: %d", decoder, err);
390                                         return -1;
391                                 }
392                                 MSG("%p: rewound.", decoder);
393                                 if(!inloop) continue;
394                         }
395                         eof = 1; /* set the flag for end of file to 1 */
396                         /* Control call call with XDM_FLUSH command */
397                         err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
398                                         decoder->dynParams, decoder->status);
399                         inBufs->numBufs = 0;
400                         outBufs->numBufs = 0;
401                         inArgs->inputID = 0;
402                 }
403                 break;
404         }
407         do {
408                 if (no_process) {
409                         /* Do not process. This is for benchmarking. We need to "fake"
410                          * the outArgs. */
411                         outArgs->outputID[0] = 0;
412                         outArgs->freeBufID[0] = 0;
413                         if(!eof) {
414                                 outArgs->outputID[0] = buf;
415                                 outArgs->freeBufID[0] = buf;
416                         }
417                         outArgs->outputID[1] = NULL;
418                         outArgs->freeBufID[1] = NULL;
419                         outArgs->outBufsInUseFlag = 0;
421                 } else {
422                         suseconds_t tproc;
423                         tproc = mark(NULL);
424                         err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
425                         DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
426                         if (err) {
427                                 ERROR("%p: process returned error: %d", decoder, err);
428                                 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
429                                 if (XDM_ISFATALERROR(outArgs->extendedError) || ( err == DCE_EXDM_UNSUPPORTED ) || ( err == DCE_EIPC_CALL_FAIL ) || ( err == DCE_EINVALID_INPUT ))
430                                         return -1;
431                         }
432                 }
434                 for (i = 0; outArgs->outputID[i]; i++) {
435                         /* calculate offset to region of interest */
436                         XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
438                         /* get the output buffer and write it to file */
439                         buf = (struct buffer *)outArgs->outputID[i];
440                         if(!no_process)
441                                disp_post_vid_buffer(decoder->disp, buf,
442                                         r->topLeft.x, r->topLeft.y,
443                                         r->bottomRight.x - r->topLeft.x,
444                                         r->bottomRight.y - r->topLeft.y);
445                 }
447                 for (i = 0; outArgs->freeBufID[i]; i++) {
448                         buf = (struct buffer *)outArgs->freeBufID[i];
449                         disp_put_vid_buffer(decoder->disp, buf);
451                         if(buf->multiplanar){
452                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
453                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
454                         }
455                         else{
456                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
457                                 DBG("FreeBufID: %p fd:%d\n", outArgs->freeBufID[i], buf->fd[0]);
458                         }
459                 }
461                 if(freeBufCount){
462                         dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
463                         freeBufCount =0;
464                 }
466                 decoder->outBufsInUseFlag = outArgs->outBufsInUseFlag;
468         } while ((err == 0) && eof && !no_process);
470         return (inBufs->numBufs > 0) ? 0 : -1;
473 /* Returns 1 (true) if the mutex is unlocked, which is the
474  * thread's signal to terminate.
475   */
477 pthread_mutex_t mtx;
479 int needQuit()
480  {
481    switch(pthread_mutex_trylock(&mtx)) {
482     case 0: /* if we got the lock, unlock and return 1 (true) */
483               pthread_mutex_unlock(&mtx);
484           return 1;
485     case EBUSY: /* return 0 (false) if the mutex was locked */
486               return 0;
487    }
488   return 1;
489   }
491 void *decode_stream(void *decoderHandle)
493         int ret = 0;
494         struct decoder *decoder = (struct decoder*)decoderHandle;
495     int n = 0;
496     if(!decoder) goto exit;
498     while((ret = decoder_process(decoder)) == 0) {
499            if(needQuit()){
500               inloop = 1;
501               break;
502             }
503          }
504     if((ret != -1 && ret != 0) && inloop) inloop = 1; /*Assuming Good case. Otherwise logic gets messy*/
505     int i = decoder->id;
506         decoder_close(decoder);
507         decoders[i]=NULL;
508 exit:
509         return NULL;
513 static void sig_handler(int signo)
515   if (signo == SIGINT) {
516           int i=0;
517           pthread_mutex_unlock(&mtx);
518           sleep(1);
519           exit(0);
520   }
524 int
525 main(int argc, char **argv)
528    int i, first = 0;
530    struct sigaction sa;
532    sa.sa_handler = sig_handler;
533    sigemptyset(&sa.sa_mask);
534    sa.sa_flags = 0;
536    if (sigaction(SIGINT, &sa, NULL) == -1) {
537      ERROR ("\nDid not catch  SIGINT\n");
538    }
539    signal(SIGINT,sig_handler);
541    pthread_mutex_init(&mtx,NULL);
542    pthread_mutex_lock(&mtx);
544     for (i = 1; i < argc; i++) {
545                 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
546                         usage(argv[0]);
547                         exit(0);
549                 } else if (!strcmp(argv[i], "--loop")) {
550                         loop = 1;
551                         argv[i] = NULL;
553                 } else if (!strcmp(argv[i], "--no-process")) {
554                         no_process = 1;
555                         argv[i] = NULL;
557                 } else if (!strcmp(argv[i], "--inloop")) {
558                         inloop = 1; // this means inloop is detected
559                         DBG("detected inloop = %d\n", inloop);
560                         loop = 1; //we want rewind as well
561                         argv[i] = NULL;
562                 } else if (!strcmp(argv[i], "--")) {
563                         argv[first] = argv[0];
564                         decoders[ndecoders] = decoder_open(i - first, &argv[first]);
565                         decoders[ndecoders]->id = ndecoders;
566                         ndecoders++;
567                         first = i;
568                 }
569         }
571         argv[first] = argv[0];
572         argc = i - first;
574         if(ndecoders) {
575             decoders[ndecoders] = decoder_open(argc ,&argv[first]);
576                 decoders[ndecoders]->id = ndecoders;
577                 ndecoders++;
578         }
580         if (ndecoders > 1) {
581                 pthread_t threadIds[8];
583                 for (i = 0; i < ndecoders; i++) {
584                         if (decoders[i]) {
585                                 int ret = pthread_create(&threadIds[i], NULL,
586                                                 &decode_stream, decoders[i]);
587                                 if (ret != 0)
588                                         ERROR("%p: creation of pthread, error: %d",
589                                                         decoders[i], ret);
590                         }
591                 }
593                 for (i = 0; i < ndecoders; i++) {
594                         pthread_join(threadIds[i], NULL);
595                 }
596         }
597         else {
598                 int itr = 0;
599                 do {
600                         decoders[0] = decoder_open(argc, &argv[first]);
601                         decoders[0]->id = 0;
602                         ndecoders++;
603                         decode_stream(decoders[0]);
604                         if (inloop) {
605                                 MSG("=================Iteration %d complete =============== %d\n", ++itr);
606                         }
607                 }while(inloop);
608         }
610         return 0;