viddec3test: new option --loop
[gstreamer-omap: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
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21
22 #include <dce.h>
23 #include <xdc/std.h>
24 #include <ti/xdais/xdas.h>
25 #include <ti/sdo/ce/Engine.h>
26 #include <ti/sdo/ce/video3/viddec3.h>
27
28 #include "util.h"
29 #include "demux.h"
30
31 /* Padding for width as per Codec Requirement (for h264) */
32 #define PADX  32
33 /* Padding for height as per Codec requirement (for h264)*/
34 #define PADY  24
35
36 struct decoder {
37         struct display *disp;
38         struct demux *demux;
39         struct buffer *framebuf;
40
41         Engine_Handle engine;
42         VIDDEC3_Handle codec;
43         VIDDEC3_Params *params;
44         VIDDEC3_DynamicParams *dynParams;
45         VIDDEC3_Status *status;
46         XDM2_BufDesc *inBufs;
47         XDM2_BufDesc *outBufs;
48         VIDDEC3_InArgs *inArgs;
49         VIDDEC3_OutArgs *outArgs;
50
51         char *input;
52         struct omap_bo *input_bo;
53         int input_sz;
54
55         suseconds_t tdisp;
56
57 };
58
59 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
60 static int no_process = 0;
61
62 /* When true, loop at end of playback. */
63 static int loop = 0;
64
65 static void
66 usage(char *name)
67 {
68         MSG("Usage: %s [OPTIONS] INFILE", name);
69         MSG("Test of viddec3 decoder.");
70         MSG("");
71         MSG("viddec3test options:");
72         MSG("\t-h, --help: Print this help and exit.");
73         MSG("\t--loop\tRestart playback at end of stream.");
74         MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
75         MSG("");
76         disp_usage();
77 }
78
79 static void
80 decoder_close(struct decoder *decoder)
81 {
82         if (decoder->codec)          VIDDEC3_delete(decoder->codec);
83         if (decoder->engine)         Engine_close(decoder->engine);
84         if (decoder->params)         dce_free(decoder->params);
85         if (decoder->dynParams)      dce_free(decoder->dynParams);
86         if (decoder->status)         dce_free(decoder->status);
87         if (decoder->inBufs)         free(decoder->inBufs);
88         if (decoder->outBufs)        free(decoder->outBufs);
89         if (decoder->inArgs)         dce_free(decoder->inArgs);
90         if (decoder->outArgs)        dce_free(decoder->outArgs);
91         if (decoder->input_bo)       omap_bo_del(decoder->input_bo);
92         if (decoder->demux)          demux_deinit(decoder->demux);
93         if (decoder->disp)           disp_close(decoder->disp);
94
95         free(decoder);
96 }
97
98 static struct decoder *
99 decoder_open(int argc, char **argv)
100 {
101         struct decoder *decoder;
102         char *infile = NULL;
103         int i, num_buffers;
104         int width, height, padded_width, padded_height;
105         Engine_Error ec;
106         XDAS_Int32 err;
107
108         decoder = calloc(1, sizeof(*decoder));
109         if (!decoder)
110                 return NULL;
111
112         MSG("%p: Opening Display..", decoder);
113         decoder->disp = disp_open(argc, argv);
114         if (!decoder->disp)
115                 goto usage;
116
117         /* loop thru args, find input file.. */
118         for (i = 1; i < argc; i++) {
119                 int fd;
120                 if (!argv[i]) {
121                         continue;
122                 }
123                 fd = open(argv[i], 0);
124                 if (fd > 0) {
125                         infile = argv[i];
126                         argv[i] = NULL;
127                         close(fd);
128                         break;
129                 }
130                 break;
131         }
132
133         if (check_args(argc, argv) || !infile)
134                 goto usage;
135
136         MSG("%p: Opening Demuxer..", decoder);
137         decoder->demux = demux_init(infile, &width, &height);
138         if (!decoder->demux) {
139                 ERROR("%p: could not open demuxer", decoder);
140                 goto fail;
141         }
142
143         MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
144
145         /* calculate output buffer parameters: */
146         width  = ALIGN2 (width, 4);        /* round up to macroblocks */
147         height = ALIGN2 (height, 4);       /* round up to macroblocks */
148         padded_width  = ALIGN2 (width + (2*PADX), 7);
149         padded_height = height + 4*PADY;
150         num_buffers   = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
151
152         MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
153                         decoder, padded_width, padded_height, num_buffers);
154
155         decoder->input_sz = width * height;
156         decoder->input_bo = omap_bo_new(decoder->disp->dev,
157                         decoder->input_sz, OMAP_BO_WC);
158         decoder->input = omap_bo_map(decoder->input_bo);
159
160         decoder->framebuf = disp_get_fb(decoder->disp);
161
162         if (! disp_get_vid_buffers(decoder->disp, num_buffers,
163                         FOURCC_STR("NV12"), padded_width, padded_height)) {
164                 ERROR("%p: could not allocate buffers", decoder);
165                 goto fail;
166         }
167
168         MSG("%p: Opening Engine..", decoder);
169         dce_set_fd(decoder->disp->fd);
170         decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
171         if (!decoder->engine) {
172                 ERROR("%p: could not open engine", decoder);
173                 goto fail;
174         }
175
176         decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
177         decoder->params->size = sizeof(IVIDDEC3_Params);
178
179         decoder->params->maxWidth         = width;
180         decoder->params->maxHeight        = height;
181         decoder->params->maxFrameRate     = 30000;
182         decoder->params->maxBitRate       = 10000000;
183         decoder->params->dataEndianness   = XDM_BYTE;
184         decoder->params->forceChromaFormat= XDM_YUV_420SP;
185         decoder->params->operatingMode    = IVIDEO_DECODE_ONLY;
186         decoder->params->displayDelay     = IVIDDEC3_DISPLAY_DELAY_AUTO;
187         decoder->params->displayBufsMode  = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
188 MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
189         decoder->params->inputDataMode    = IVIDEO_ENTIREFRAME;
190         decoder->params->metadataType[0]  = IVIDEO_METADATAPLANE_NONE;
191         decoder->params->metadataType[1]  = IVIDEO_METADATAPLANE_NONE;
192         decoder->params->metadataType[2]  = IVIDEO_METADATAPLANE_NONE;
193         decoder->params->numInputDataUnits= 0;
194         decoder->params->outputDataMode   = IVIDEO_ENTIREFRAME;
195         decoder->params->numOutputDataUnits = 0;
196         decoder->params->errorInfoMode    = IVIDEO_ERRORINFO_OFF;
197
198         decoder->codec = VIDDEC3_create(decoder->engine,
199                         "ivahd_h264dec", decoder->params);
200         if (!decoder->codec) {
201                 ERROR("%p: could not create codec", decoder);
202                 goto fail;
203         }
204
205         decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
206         decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
207
208         decoder->dynParams->decodeHeader  = XDM_DECODE_AU;
209
210         /*Not Supported: Set default*/
211         decoder->dynParams->displayWidth  = 0;
212         decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
213         decoder->dynParams->newFrameFlag  = XDAS_TRUE;
214
215         decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
216         decoder->status->size = sizeof(IVIDDEC3_Status);
217
218         err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
219                         decoder->dynParams, decoder->status);
220         if (err) {
221                 ERROR("%p: fail: %d", decoder, err);
222                 goto fail;
223         }
224
225         /* not entirely sure why we need to call this here.. just copying omx.. */
226         err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
227                         decoder->dynParams, decoder->status);
228         if (err) {
229                 ERROR("%p: fail: %d", decoder, err);
230                 goto fail;
231         }
232
233         decoder->inBufs = calloc(1, sizeof(XDM2_BufDesc));
234         decoder->inBufs->numBufs = 1;
235         decoder->inBufs->descs[0].buf =
236                         (XDAS_Int8 *)omap_bo_handle(decoder->input_bo);
237         decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
238         decoder->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
239
240         decoder->outBufs = calloc(1, sizeof(XDM2_BufDesc));
241         decoder->outBufs->numBufs = 2;
242         decoder->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
243         decoder->outBufs->descs[1].memType = XDM_MEMTYPE_BO;
244
245         decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
246         decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
247
248         decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
249         decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
250
251         decoder->tdisp = mark(NULL);
252
253         return decoder;
254
255 usage:
256         usage(argv[0]);
257 fail:
258         if (decoder)
259                 decoder_close(decoder);
260         return NULL;
261 }
262
263 static int
264 decoder_process(struct decoder *decoder)
265 {
266         XDM2_BufDesc *inBufs = decoder->inBufs;
267         XDM2_BufDesc *outBufs = decoder->outBufs;
268         VIDDEC3_InArgs *inArgs = decoder->inArgs;
269         VIDDEC3_OutArgs *outArgs = decoder->outArgs;
270         struct buffer *buf;
271         int i, n;
272
273         buf = disp_get_vid_buffer(decoder->disp);
274         if (!buf) {
275                 ERROR("%p: fail: out of buffers", decoder);
276                 return -1;
277         }
278
279         /* demux; in loop mode, we can do two tries at the end of the stream. */
280         for (i = 0; i < 2; i++) {
281                 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
282                 if (n) {
283                         inBufs->descs[0].bufSize.bytes = n;
284                         inArgs->numBytes = n;
285                         DBG("%p: push: %d bytes (%p)", decoder, n, buf);
286                 } else {
287                         /* end of input.. do we need to flush? */
288                         MSG("%p: end of input", decoder);
289
290                         /* In loop mode: rewind and retry once. */
291                         if (loop && i == 0) {
292                                 int err = demux_rewind(decoder->demux);
293                                 if (err < 0) {
294                                         ERROR("%p: demux_rewind returned error: %d", decoder, err);
295                                         return -1;
296                                 }
297                                 MSG("%p: rewound.", decoder);
298                                 continue;
299                         }
300
301                         /* Not in loop or second try: end. */
302                         inBufs->numBufs = 0;
303                         inArgs->inputID = 0;
304                 }
305                 break;
306         }
307
308         inArgs->inputID = (XDAS_Int32)buf;
309         outBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_handle(buf->bo[0]);
310         outBufs->descs[0].bufSize.bytes = omap_bo_size(buf->bo[0]);
311         outBufs->descs[1].buf = (XDAS_Int8 *)omap_bo_handle(buf->bo[1]);
312         outBufs->descs[1].bufSize.bytes = omap_bo_size(buf->bo[1]);
313
314         if (no_process) {
315                 /* Do not process. This is for benchmarking. We need to "fake"
316                  * the outArgs. */
317                 outArgs->outputID[0] = buf;
318                 outArgs->outputID[1] = NULL;
319                 outArgs->freeBufID[0] = buf;
320                 outArgs->freeBufID[1] = NULL;
321                 outArgs->outBufsInUseFlag = 0;
322
323         } else {
324                 XDAS_Int32 err;
325                 suseconds_t tproc;
326                 tproc = mark(NULL);
327                 err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
328                 DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
329                 if (err) {
330                         ERROR("%p: process returned error: %d", decoder, err);
331                         ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
332                         if (XDM_ISFATALERROR(outArgs->extendedError))
333                                 return -1;
334                 }
335         }
336
337         for (i = 0; outArgs->outputID[i]; i++) {
338                 /* calculate offset to region of interest */
339                 XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
340
341                 /* get the output buffer and write it to file */
342                 buf = (struct buffer *)outArgs->outputID[i];
343                 DBG("%p: post buffer: %p %d,%d %d,%d", decoder, buf,
344                                 r->topLeft.x, r->topLeft.y,
345                                 r->bottomRight.x, r->bottomRight.y);
346                 disp_post_vid_buffer(decoder->disp, buf,
347                                 r->topLeft.x, r->topLeft.y,
348                                 r->bottomRight.x - r->topLeft.x,
349                                 r->bottomRight.y - r->topLeft.y);
350                 DBG("%p: display in: %ldus", decoder, (long int)mark(&decoder->tdisp));
351         }
352
353         for (i = 0; outArgs->freeBufID[i]; i++) {
354                 buf = (struct buffer *)outArgs->freeBufID[i];
355                 disp_put_vid_buffer(decoder->disp, buf);
356         }
357
358         if (outArgs->outBufsInUseFlag) {
359                 MSG("%p: TODO... outBufsInUseFlag", decoder); // XXX
360         }
361
362         return (inBufs->numBufs > 0) ? 0 : -1;
363 }
364
365 int
366 main(int argc, char **argv)
367 {
368         struct decoder *decoders[8] = {};
369         int i, n, first = 0, ndecoders = 0;
370
371         for (i = 1; i < argc; i++) {
372                 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
373                         usage(argv[0]);
374                         exit(0);
375
376                 } else if (!strcmp(argv[i], "--loop")) {
377                         loop = 1;
378                         argv[i] = NULL;
379
380                 } else if (!strcmp(argv[i], "--no-process")) {
381                         no_process = 1;
382                         argv[i] = NULL;
383
384                 } else if (!strcmp(argv[i], "--")) {
385                         argv[first] = argv[0];
386                         decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
387                         first = i;
388                 }
389         }
390
391         argv[first] = argv[0];
392         decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
393
394         do {
395                 for (i = 0, n = 0; i < ndecoders; i++) {
396                         if (decoders[i]) {
397                                 int ret = decoder_process(decoders[i]);
398                                 if (ret) {
399                                         decoder_close(decoders[i]);
400                                         decoders[i] = NULL;
401                                         continue;
402                                 }
403                                 n++;
404                         }
405                 }
406         } while(n > 0);
407
408         return 0;
409 }