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 "util.h"
26 #include "demux.h"
28 /* Used for mpeg4 esds data copy */
29 int first_in_buff = 0;
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 /* omap drm device handle */
36 struct omap_device *dev = NULL;
38 struct decoder {
39 struct display *disp;
40 struct demux *demux;
41 struct buffer *framebuf;
42 Engine_Handle engine;
43 VIDDEC3_Handle codec;
44 VIDDEC3_Params *params;
45 VIDDEC3_DynamicParams *dynParams;
46 VIDDEC3_Status *status;
47 XDM2_BufDesc *inBufs;
48 XDM2_BufDesc *outBufs;
49 VIDDEC3_InArgs *inArgs;
50 VIDDEC3_OutArgs *outArgs;
51 char *input;
52 struct omap_bo *input_bo;
53 int input_sz, uv_offset;
54 int padded_width;
55 int padded_height;
56 int num_outBuf;
57 size_t *outBuf_fd;
58 suseconds_t tdisp;
59 };
61 /* When true, do not actually call VIDDEC3_process. For benchmarking. */
62 static int no_process = 0;
64 /* When true, loop at end of playback. */
65 static int loop = 0;
67 static void
68 usage(char *name)
69 {
70 MSG("Usage: %s [OPTIONS] INFILE", name);
71 MSG("Test of viddec3 decoder.");
72 MSG("");
73 MSG("viddec3test options:");
74 MSG("\t-h, --help: Print this help and exit.");
75 MSG("\t--loop\tRestart playback at end of stream.");
76 MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
77 MSG("");
78 disp_usage();
79 }
81 static void
82 decoder_close(struct decoder *decoder)
83 {
84 /* free output buffers allocated by display */
85 disp_free_buffers(decoder->disp,decoder->num_outBuf);
87 if (decoder->codec) VIDDEC3_delete(decoder->codec);
88 if (decoder->engine) Engine_close(decoder->engine);
89 if (dev) dce_deinit(dev);
90 if (decoder->params) dce_free(decoder->params);
91 if (decoder->dynParams) dce_free(decoder->dynParams);
92 if (decoder->status) dce_free(decoder->status);
93 if (decoder->inBufs) dce_free(decoder->inBufs);
94 if (decoder->outBufs) dce_free(decoder->outBufs);
95 if (decoder->inArgs) dce_free(decoder->inArgs);
96 if (decoder->outArgs) dce_free(decoder->outArgs);
97 if (decoder->input_bo) omap_bo_del(decoder->input_bo);
98 if (decoder->demux) demux_deinit(decoder->demux);
99 if (decoder->disp) disp_close(decoder->disp);
100 if (decoder->outBuf_fd) free(decoder->outBuf_fd);
101 free(decoder);
102 }
104 static struct decoder *
105 decoder_open(int argc, char **argv)
106 {
107 struct decoder *decoder;
108 char *infile = NULL;
109 int i;
110 int width, height, padded_width, padded_height;
111 Engine_Error ec;
112 XDAS_Int32 err;
114 decoder = calloc(1, sizeof(*decoder));
115 if (!decoder)
116 return NULL;
118 MSG("%p: Opening Display..", decoder);
119 decoder->disp = disp_open(argc, argv);
120 if (!decoder->disp)
121 goto usage;
123 /* loop thru args, find input file.. */
124 for (i = 1; i < argc; i++) {
125 int fd;
126 if (!argv[i]) {
127 continue;
128 }
129 fd = open(argv[i], 0);
130 if (fd > 0) {
131 infile = argv[i];
132 argv[i] = NULL;
133 close(fd);
134 break;
135 }
136 break;
137 }
139 if (check_args(argc, argv) || !infile)
140 goto usage;
142 MSG("%p: Opening Demuxer..", decoder);
143 decoder->demux = demux_init(infile, &width, &height);
144 if (!decoder->demux) {
145 ERROR("%p: could not open demuxer", decoder);
146 goto fail;
147 }
149 MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
151 /* calculate output buffer parameters: */
152 width = ALIGN2 (width, 4); /* round up to macroblocks */
153 height = ALIGN2 (height, 4); /* round up to macroblocks */
155 if (decoder->demux->cc->codec_id == CODEC_ID_MPEG2VIDEO) {
156 padded_width = width;
157 padded_height= height;
158 }
159 else {
160 padded_width = ALIGN2 (width + (2*PADX), 7);
161 padded_height = height + 4*PADY;
162 }
164 decoder->num_outBuf = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
165 decoder->padded_width = padded_width;
166 decoder->padded_height = padded_height;
167 MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
168 decoder, padded_width, padded_height, decoder->num_outBuf);
170 if (!decoder->disp->multiplanar) {
171 decoder->uv_offset = padded_width * padded_height;
172 decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
173 MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
174 }
175 else{
176 decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
177 }
179 decoder->input_sz = width * height;
180 decoder->input_bo = omap_bo_new(decoder->disp->dev,
181 decoder->input_sz, OMAP_BO_WC);
182 decoder->input = omap_bo_map(decoder->input_bo);
183 decoder->framebuf = disp_get_fb(decoder->disp);
185 if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
186 FOURCC_STR("NV12"), padded_width, padded_height)) {
187 ERROR("%p: could not allocate buffers", decoder);
188 goto fail;
189 }
191 MSG("%p: Opening Engine..", decoder);
192 dce_set_fd(decoder->disp->fd);
193 dev = dce_init();
194 if(dev == NULL) {
195 ERROR("%p: dce init failed", dev);
196 goto fail;
197 }
198 decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
199 if (!decoder->engine) {
200 ERROR("%p: could not open engine", decoder);
201 goto fail;
202 }
204 decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
205 decoder->params->size = sizeof(IVIDDEC3_Params);
207 decoder->params->maxWidth = width;
208 decoder->params->maxHeight = height;
209 decoder->params->maxFrameRate = 30000;
210 decoder->params->maxBitRate = 10000000;
211 decoder->params->dataEndianness = XDM_BYTE;
212 decoder->params->forceChromaFormat= XDM_YUV_420SP;
213 decoder->params->operatingMode = IVIDEO_DECODE_ONLY;
214 decoder->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
215 decoder->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
216 MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
217 decoder->params->inputDataMode = IVIDEO_ENTIREFRAME;
218 decoder->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
219 decoder->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
220 decoder->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
221 decoder->params->numInputDataUnits= 0;
222 decoder->params->outputDataMode = IVIDEO_ENTIREFRAME;
223 decoder->params->numOutputDataUnits = 0;
224 decoder->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
226 if (decoder->demux->cc->codec_id == CODEC_ID_MPEG2VIDEO) {
227 decoder->codec = VIDDEC3_create(decoder->engine,
228 "ivahd_mpeg2vdec", decoder->params);
229 }
230 else if (decoder->demux->cc->codec_id == CODEC_ID_H264) {
231 decoder->codec = VIDDEC3_create(decoder->engine,
232 "ivahd_h264dec", decoder->params);
233 }
234 else if (decoder->demux->cc->codec_id == CODEC_ID_MPEG4) {
235 first_in_buff = 1;
236 decoder->codec = VIDDEC3_create(decoder->engine,
237 "ivahd_mpeg4dec", decoder->params);
238 }
240 if (!decoder->codec) {
241 ERROR("%p: could not create codec", decoder);
242 goto fail;
243 }
245 decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
246 decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
248 decoder->dynParams->decodeHeader = XDM_DECODE_AU;
250 /*Not Supported: Set default*/
251 decoder->dynParams->displayWidth = 0;
252 decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
253 decoder->dynParams->newFrameFlag = XDAS_TRUE;
255 decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
256 decoder->status->size = sizeof(IVIDDEC3_Status);
258 err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
259 decoder->dynParams, decoder->status);
260 if (err) {
261 ERROR("%p: fail: %d", decoder, err);
262 goto fail;
263 }
265 /* not entirely sure why we need to call this here.. just copying omx.. */
266 err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
267 decoder->dynParams, decoder->status);
268 if (err) {
269 ERROR("%p: fail: %d", decoder, err);
270 goto fail;
271 }
273 decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
274 decoder->inBufs->numBufs = 1;
275 decoder->inBufs->descs[0].buf = (XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
276 decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
277 decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
280 decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
281 decoder->outBufs->numBufs = 2;
282 decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
283 decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
285 decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
286 decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
288 decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
289 decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
291 decoder->tdisp = mark(NULL);
293 return decoder;
295 usage:
296 usage(argv[0]);
297 fail:
298 if (decoder)
299 decoder_close(decoder);
300 return NULL;
301 }
303 static int
304 decoder_process(struct decoder *decoder)
305 {
306 XDM2_BufDesc *inBufs = decoder->inBufs;
307 XDM2_BufDesc *outBufs = decoder->outBufs;
308 VIDDEC3_InArgs *inArgs = decoder->inArgs;
309 VIDDEC3_OutArgs *outArgs = decoder->outArgs;
310 struct buffer *buf;
311 int freeBufCount =0;
312 int i, n;
313 XDAS_Int32 err;
314 int eof = 0; /* end of file flag */
316 buf = disp_get_vid_buffer(decoder->disp);
317 if (!buf) {
318 ERROR("%p: fail: out of buffers", decoder);
319 return -1;
320 }
322 /* demux; in loop mode, we can do two tries at the end of the stream. */
323 for (i = 0; i < 2; i++) {
324 n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
325 if (n) {
327 inBufs->descs[0].bufSize.bytes = n;
328 inArgs->numBytes = n;
329 DBG("%p: push: %d bytes (%p)", decoder, n, buf);
330 } else {
331 /* end of input.. do we need to flush? */
332 MSG("%p: end of input", decoder);
334 /* In loop mode: rewind and retry once. */
335 if (loop && i == 0) {
336 int err = demux_rewind(decoder->demux);
337 if (err < 0) {
338 ERROR("%p: demux_rewind returned error: %d", decoder, err);
339 return -1;
340 }
341 MSG("%p: rewound.", decoder);
342 continue;
343 }
344 eof = 1; /* set the flag for end of file to 1 */
345 /* Control call call with XDM_FLUSH command */
346 err = VIDDEC3_control(decoder->codec, XDM_FLUSH,
347 decoder->dynParams, decoder->status);
348 inBufs->numBufs = 0;
349 inArgs->inputID = 0;
350 }
351 break;
352 }
354 /*set the parameters if it is not the end of file */
355 if (!eof) {
356 inArgs->inputID = (XDAS_Int32)buf;
357 outBufs->descs[0].buf = buf->fd[0];
358 outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
361 if(buf->multiplanar){
362 decoder->outBuf_fd[0] = buf->fd[0];
363 decoder->outBuf_fd[1] = buf->fd[1];
364 dce_buf_lock(2,decoder->outBuf_fd);
365 }
366 else{
367 decoder->outBuf_fd[0] = buf->fd[0];
368 dce_buf_lock(1,decoder->outBuf_fd);
369 }
370 decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
371 decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
372 }
374 do {
375 if (no_process) {
376 /* Do not process. This is for benchmarking. We need to "fake"
377 * the outArgs. */
378 outArgs->outputID[0] = buf;
379 outArgs->outputID[1] = NULL;
380 outArgs->freeBufID[0] = buf;
381 outArgs->freeBufID[1] = NULL;
382 outArgs->outBufsInUseFlag = 0;
384 } else {
385 suseconds_t tproc;
386 tproc = mark(NULL);
387 err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
388 DBG("%p: processed returned in: %ldus", decoder, (long int)mark(&tproc));
389 if (err) {
390 ERROR("%p: process returned error: %d", decoder, err);
391 ERROR("%p: extendedError: %08x", decoder, outArgs->extendedError);
392 if (XDM_ISFATALERROR(outArgs->extendedError))
393 return -1;
394 }
395 }
397 for (i = 0; outArgs->outputID[i]; i++) {
398 /* calculate offset to region of interest */
399 XDM_Rect *r = &(outArgs->displayBufs.bufDesc[0].activeFrameRegion);
401 /* get the output buffer and write it to file */
402 buf = (struct buffer *)outArgs->outputID[i];
403 disp_post_vid_buffer(decoder->disp, buf,
404 r->topLeft.x, r->topLeft.y,
405 r->bottomRight.x - r->topLeft.x,
406 r->bottomRight.y - r->topLeft.y);
407 }
409 for (i = 0; outArgs->freeBufID[i]; i++) {
410 buf = (struct buffer *)outArgs->freeBufID[i];
411 disp_put_vid_buffer(decoder->disp, buf);
413 if(buf->multiplanar){
414 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
415 decoder->outBuf_fd[freeBufCount++] = buf->fd[1];
416 }
417 else{
418 decoder->outBuf_fd[freeBufCount++] = buf->fd[0];
419 }
420 }
422 if(freeBufCount){
423 dce_buf_unlock(freeBufCount,decoder->outBuf_fd);
424 freeBufCount =0;
425 }
426 if (outArgs->outBufsInUseFlag) {
427 MSG("%p: TODO... outBufsInUseFlag", decoder); // XXX
428 }
429 } while ((err == 0) && eof);
431 return (inBufs->numBufs > 0) ? 0 : -1;
432 }
434 int
435 main(int argc, char **argv)
436 {
437 struct decoder *decoders[8] = {};
438 int i, n, first = 0, ndecoders = 0;
440 for (i = 1; i < argc; i++) {
441 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
442 usage(argv[0]);
443 exit(0);
445 } else if (!strcmp(argv[i], "--loop")) {
446 loop = 1;
447 argv[i] = NULL;
449 } else if (!strcmp(argv[i], "--no-process")) {
450 no_process = 1;
451 argv[i] = NULL;
453 } else if (!strcmp(argv[i], "--")) {
454 argv[first] = argv[0];
455 decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
456 first = i;
457 }
458 }
460 argv[first] = argv[0];
461 decoders[ndecoders++] = decoder_open(i - first, &argv[first]);
463 do {
464 for (i = 0, n = 0; i < ndecoders; i++) {
465 if (decoders[i]) {
466 int ret = decoder_process(decoders[i]);
467 if (ret) {
468 decoder_close(decoders[i]);
469 decoders[i] = NULL;
470 continue;
471 }
472 n++;
473 }
474 }
475 } while(n > 0);
477 return 0;
478 }