viddec3test: Close the duplicate fd's created from omap_bo_dmabuf
[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>
25 #include <pthread.h>
27 #include "util.h"
28 #include "demux.h"
30 /* Used for mpeg4 esds data copy */
31 int first_in_buff = 0;
33 /* Padding for width as per Codec Requirement (for h264) */
34 #define PADX  32
35 /* Padding for height as per Codec requirement (for h264)*/
36 #define PADY  24
37 /* omap drm device handle */
38 struct omap_device *dev = NULL;
40 struct decoder {
41         struct display *disp;
42         struct demux *demux;
43         struct buffer *framebuf;
44         Engine_Handle engine;
45         VIDDEC3_Handle codec;
46         VIDDEC3_Params *params;
47         VIDDEC3_DynamicParams *dynParams;
48         VIDDEC3_Status *status;
49         XDM2_BufDesc *inBufs;
50         XDM2_BufDesc *outBufs;
51         VIDDEC3_InArgs *inArgs;
52         VIDDEC3_OutArgs *outArgs;
53         char *input;
54         struct omap_bo *input_bo;
55         int input_sz, uv_offset;
56         int padded_width;
57         int padded_height;
58         int num_outBuf;
59         size_t *outBuf_fd;
60         suseconds_t tdisp;
61 };
63 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
64 static int no_process = 0;
66 /* When true, loop at end of playback. */
67 static int loop = 0;
69 static void
70 usage(char *name)
71 {
72         MSG("Usage: %s [OPTIONS] INFILE", name);
73         MSG("Test of viddec3 decoder.");
74         MSG("");
75         MSG("viddec3test options:");
76         MSG("\t-h, --help: Print this help and exit.");
77         MSG("\t--loop\tRestart playback at end of stream.");
78         MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
79         MSG("");
80         disp_usage();
81 }
83 static void
84 decoder_close(struct decoder *decoder)
85 {
86         /* free output buffers allocated by display */
87         disp_free_buffers(decoder->disp,decoder->num_outBuf);
89         if (decoder->status)         dce_free(decoder->status);
90         if (decoder->params)         dce_free(decoder->params);
91         if (decoder->dynParams)      dce_free(decoder->dynParams);
92         if (decoder->inBufs)         dce_free(decoder->inBufs);
93         if (decoder->outBufs)        dce_free(decoder->outBufs);
94         if (decoder->inArgs)         dce_free(decoder->inArgs);
95         if (decoder->outArgs)        dce_free(decoder->outArgs);
96         if (decoder->codec)          VIDDEC3_delete(decoder->codec);
97         if (decoder->engine)         Engine_close(decoder->engine);
98         if (dev)                     dce_deinit(dev);
99         if (decoder->input_bo)       omap_bo_del(decoder->input_bo);
100         if (decoder->demux)          demux_deinit(decoder->demux);
101         if (decoder->disp)           disp_close(decoder->disp);
102         if (decoder->outBuf_fd)      free(decoder->outBuf_fd);
103         free(decoder);
106 static struct decoder *
107 decoder_open(int argc, char **argv)
109         struct decoder *decoder;
110         char *infile = NULL;
111         int i;
112         int width, height, padded_width, padded_height;
113         Engine_Error ec;
114         XDAS_Int32 err;
116         decoder = calloc(1, sizeof(*decoder));
117         if (!decoder)
118                 return NULL;
120         MSG("%p: Opening Display..", decoder);
121         decoder->disp = disp_open(argc, argv);
122         if (!decoder->disp)
123                 goto usage;
125         /* loop thru args, find input file.. */
126         for (i = 1; i < argc; i++) {
127                 int fd;
128                 if (!argv[i]) {
129                         continue;
130                 }
131                 fd = open(argv[i], 0);
132                 if (fd > 0) {
133                         infile = argv[i];
134                         argv[i] = NULL;
135                         close(fd);
136                         break;
137                 }
138                 break;
139         }
141         if (check_args(argc, argv) || !infile)
142                 goto usage;
144         MSG("%p: Opening Demuxer..", decoder);
145         decoder->demux = demux_init(infile, &width, &height);
146         if (!decoder->demux) {
147                 ERROR("%p: could not open demuxer", decoder);
148                 goto fail;
149         }
151         MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
153         /* calculate output buffer parameters: */
154         width  = ALIGN2 (width, 4);        /* round up to macroblocks */
155         height = ALIGN2 (height, 4);       /* round up to macroblocks */
157        if (decoder->demux->cc->codec_id == CODEC_ID_MPEG2VIDEO) {
158                 padded_width = width;
159                 padded_height= height;
160         }
161         else {
162                 padded_width  = ALIGN2 (width + (2*PADX), 7);
163                 padded_height = height + 4*PADY;
164         }
166         decoder->num_outBuf   = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
167         decoder->padded_width = padded_width;
168         decoder->padded_height = padded_height;
169         MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
170                         decoder, padded_width, padded_height, decoder->num_outBuf);
172         if (!decoder->disp->multiplanar) {
173                 decoder->uv_offset = padded_width * padded_height;
174                 decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
175                 MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
176         }
177         else{
178                 decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
179         }
181         decoder->input_sz = width * height;
182         decoder->input_bo = omap_bo_new(decoder->disp->dev,
183                         decoder->input_sz, OMAP_BO_WC);
184         decoder->input = omap_bo_map(decoder->input_bo);
185         decoder->framebuf = disp_get_fb(decoder->disp);
187         if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
188                         FOURCC_STR("NV12"), padded_width, padded_height)) {
189                 ERROR("%p: could not allocate buffers", decoder);
190                 goto fail;
191         }
193         MSG("%p: Opening Engine..", decoder);
194         dce_set_fd(decoder->disp->fd);
195         dev = dce_init();
196         if(dev == NULL) {
197                 ERROR("%p: dce init failed", dev);
198                 goto fail;
199         }
200         decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
201         if (!decoder->engine) {
202                 ERROR("%p: could not open engine", decoder);
203                 goto fail;
204         }
206         decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
207         decoder->params->size = sizeof(IVIDDEC3_Params);
209         decoder->params->maxWidth         = width;
210         decoder->params->maxHeight        = height;
211         decoder->params->maxFrameRate     = 30000;
212         decoder->params->maxBitRate       = 10000000;
213         decoder->params->dataEndianness   = XDM_BYTE;
214         decoder->params->forceChromaFormat= XDM_YUV_420SP;
215         decoder->params->operatingMode    = IVIDEO_DECODE_ONLY;
216         decoder->params->displayDelay     = IVIDDEC3_DISPLAY_DELAY_AUTO;
217         decoder->params->displayBufsMode  = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
218         MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
219         decoder->params->inputDataMode    = IVIDEO_ENTIREFRAME;
220         decoder->params->metadataType[0]  = IVIDEO_METADATAPLANE_NONE;
221         decoder->params->metadataType[1]  = IVIDEO_METADATAPLANE_NONE;
222         decoder->params->metadataType[2]  = IVIDEO_METADATAPLANE_NONE;
223         decoder->params->numInputDataUnits= 0;
224         decoder->params->outputDataMode   = IVIDEO_ENTIREFRAME;
225         decoder->params->numOutputDataUnits = 0;
226         decoder->params->errorInfoMode    = IVIDEO_ERRORINFO_OFF;
228         if (decoder->demux->cc->codec_id == CODEC_ID_MPEG2VIDEO) {
229             decoder->codec = VIDDEC3_create(decoder->engine,
230                                         "ivahd_mpeg2vdec", decoder->params);
231         }
232         else if (decoder->demux->cc->codec_id == CODEC_ID_H264) {
233             decoder->codec = VIDDEC3_create(decoder->engine,
234                                         "ivahd_h264dec", decoder->params);
235         }
236         else if (decoder->demux->cc->codec_id == CODEC_ID_MPEG4) {
237                 first_in_buff = 1;
238                 decoder->codec = VIDDEC3_create(decoder->engine,
239                                         "ivahd_mpeg4dec", decoder->params);
240         }
242         if (!decoder->codec) {
243                 ERROR("%p: could not create codec", decoder);
244                 goto fail;
245         }
247         decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
248         decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
250         decoder->dynParams->decodeHeader  = XDM_DECODE_AU;
252         /*Not Supported: Set default*/
253         decoder->dynParams->displayWidth  = 0;
254         decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
255         decoder->dynParams->newFrameFlag  = XDAS_TRUE;
257         decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
258         decoder->status->size = sizeof(IVIDDEC3_Status);
260         err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
261                         decoder->dynParams, decoder->status);
262         if (err) {
263                 ERROR("%p: fail: %d", decoder, err);
264                 goto fail;
265         }
267         /* not entirely sure why we need to call this here.. just copying omx.. */
268         err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
269                         decoder->dynParams, decoder->status);
270         if (err) {
271                 ERROR("%p: fail: %d", decoder, err);
272                 goto fail;
273         }
275         decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
276         decoder->inBufs->numBufs = 1;
277         decoder->inBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
278         decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
279         decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
282         decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
283         decoder->outBufs->numBufs = 2;
284         decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
285         decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
287         decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
288         decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
290         decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
291         decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
293         decoder->tdisp = mark(NULL);
295         return decoder;
297 usage:
298         usage(argv[0]);
299 fail:
300         if (decoder)
301                 decoder_close(decoder);
302         return NULL;
305 static int
306 decoder_process(struct decoder *decoder)
308         XDM2_BufDesc *inBufs = decoder->inBufs;
309         XDM2_BufDesc *outBufs = decoder->outBufs;
310         VIDDEC3_InArgs *inArgs = decoder->inArgs;
311         VIDDEC3_OutArgs *outArgs = decoder->outArgs;
312         struct buffer *buf;
313         int freeBufCount =0;
314         int i, n;
315         XDAS_Int32 err;
316         int eof = 0; /* end of file flag */
318         buf = disp_get_vid_buffer(decoder->disp);
319         if (!buf) {
320                 ERROR("%p: fail: out of buffers", decoder);
321                 return -1;
322         }
324         /* demux; in loop mode, we can do two tries at the end of the stream. */
325         for (i = 0; i < 2; i++) {
326                 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
327                 if (n) {
329                         inBufs->descs[0].bufSize.bytes = n;
330                         inArgs->numBytes = n;
331                         DBG("%p: push: %d bytes (%p)", decoder, n, buf);
332                 } else {
333                         /* end of input.. do we need to flush? */
334                         MSG("%p: end of input", decoder);
336                         /* In loop mode: rewind and retry once. */
337                         if (loop && i == 0) {
338                                 int err = demux_rewind(decoder->demux);
339                                 if (err < 0) {
340                                         ERROR("%p: demux_rewind returned error: %d", decoder, err);
341                                         return -1;
342                                 }
343                                 MSG("%p: rewound.", decoder);
344                                 continue;
345                         }
346                         eof = 1; /* set the flag for end of file to 1 */
347                         /* Control call call with XDM_FLUSH command */
348                         err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
349                                         decoder->dynParams, decoder->status);
350                         inBufs->numBufs = 0;
351                         inArgs->inputID = 0;
352                 }
353                 break;
354         }
356         /*set the parameters if it is not the end of file */
357         if (!eof) {
358                 inArgs->inputID = (XDAS_Int32)buf;
359                 outBufs->descs[0].buf = buf->fd[0];
360                 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
363                 if(buf->multiplanar){
364                         decoder->outBuf_fd[0] = buf->fd[0];
365                         decoder->outBuf_fd[1] = buf->fd[1];
366                         dce_buf_lock(2,decoder->outBuf_fd);
367                 }
368                 else{
369                         decoder->outBuf_fd[0] = buf->fd[0];
370                         dce_buf_lock(1,decoder->outBuf_fd);
371                 }
372                 decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
373                 decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
374         }
376         do {
377                 if (no_process) {
378                         /* Do not process. This is for benchmarking. We need to "fake"
379                          * the outArgs. */
380                         outArgs->outputID[0] = buf;
381                         outArgs->outputID[1] = NULL;
382                         outArgs->freeBufID[0] = buf;
383                         outArgs->freeBufID[1] = NULL;
384                         outArgs->outBufsInUseFlag = 0;
386                 } else {
387                         suseconds_t tproc;
388                         tproc = mark(NULL);
389                         err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
390                         DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
391                         if (err) {
392                                 ERROR("%p: process returned error: %d", decoder, err);
393                                 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
394                                 if (XDM_ISFATALERROR(outArgs->extendedError))
395                                         return -1;
396                         }
397                 }
399                 for (i = 0; outArgs->outputID[i]; i++) {
400                         /* calculate offset to region of interest */
401                         XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
403                         /* get the output buffer and write it to file */
404                         buf = (struct buffer *)outArgs->outputID[i];
405                         disp_post_vid_buffer(decoder->disp, buf,
406                                         r->topLeft.x, r->topLeft.y,
407                                         r->bottomRight.x - r->topLeft.x,
408                                         r->bottomRight.y - r->topLeft.y);
409                 }
411                 for (i = 0; outArgs->freeBufID[i]; i++) {
412                         buf = (struct buffer *)outArgs->freeBufID[i];
413                         disp_put_vid_buffer(decoder->disp, buf);
415                         if(buf->multiplanar){
416                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
417                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
418                         }
419                         else{
420                                 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
421                         }
422                 }
424                 if(freeBufCount){
425                         dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
426                         freeBufCount =0;
427                 }
428                 if (outArgs->outBufsInUseFlag) {
429                         MSG("%p: TODO... outBufsInUseFlag", decoder); // XXX
430                 }
431         } while ((err == 0) && eof);
433         return (inBufs->numBufs > 0) ? 0 : -1;
436 void *decode_stream(void *decoderHandle)
438         int n = 0;
439         struct decoder *decoders = (struct decoder*)decoderHandle;
441         do {
442                 if (decoders) {
443                         int ret = decoder_process(decoders);
444                         if (ret) {
445                                 decoder_close(decoders);
446                                 decoders = NULL;
447                                 n = 0;
448                                 continue;
449                         }
450                         n++;
451                 }
452         } while(n > 0);
454         return NULL;
457 int
458 main(int argc, char **argv)
460         struct decoder *decoders[8] = {};
461         int i, first = 0, ndecoders = 0;
463         for (i = 1; i < argc; i++) {
464                 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
465                         usage(argv[0]);
466                         exit(0);
468                 } else if (!strcmp(argv[i], "--loop")) {
469                         loop = 1;
470                         argv[i] = NULL;
472                 } else if (!strcmp(argv[i], "--no-process")) {
473                         no_process = 1;
474                         argv[i] = NULL;
476                 } else if (!strcmp(argv[i], "--")) {
477                         argv[first] = argv[0];
478                         decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
479                         first = i;
480                 }
481         }
483         argv[first] = argv[0];
485         decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
487         if (ndecoders > 1) {
488                 pthread_t threadIds[8];
490                 for (i = 0; i < ndecoders; i++) {
491                         if (decoders[i]) {
492                                 int ret = pthread_create(&threadIds[i], NULL,
493                                                 &decode_stream, decoders[i]);
494                                 if (ret != 0)
495                                         ERROR("%p: creation of pthread, error: %d",
496                                                         decoders[i], ret);
497                         }
498                 }
500                 for (i = 0; i < ndecoders; i++) {
501                         pthread_join(threadIds[i], NULL);
502                 }
503         }
504         else {
505                 decode_stream(decoders[0]);
506         }
508         return 0;