This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/DRA746: how to configure mpeg4 stream

Part Number: DRA746

Tool/software: Linux

Hi Ram,
I have problem with mpeg4 format. I want to parse the stream header to get the width and height.
Refering to appendix Dof MPEG4 decoder user guide, Parsing the header from mpeg4 stream seems not work well, whose procedure is the same as 264 stream.
calling VIDDEC3_process and return -1 error, and extendedError is XDM_UNSUPPORTEDPARAM. I cannot find the root cause.
The stream header containing VOS + VO + VOL +VOP is below,
11-13 21:09:04.698 17839 17847 D hexDump: 0000: 00, 00, 01, b0, f5, 00, 00, 01, b5, 09, 00, 00, 01, 00, 00, 00,
11-13 21:09:04.698 17839 17847 D hexDump: 0010: 01, 20, 00, 84, 5d, 4c, 28, a0, 21, e0, a3, 1f, 00, 00, 01, b6
Is the stream is right or not?

  • Hi Gao,

    I modified viddec3test for this, I am able to get width and height detected properly. Please refer this. But I am still using demuxer to fill one complete frame. Without allocating outputbuffer is throwing error.

    I tried this for stream /usr/share/ti/video/HistoryOfTI-480p.m4v

    /*
     * Copyright (C) 2012 Texas Instruments
     * Author: Rob Clark <rob.clark@linaro.org>
     *
     * This program is free software; you can redistribute it and/or modify it
     * under the terms of the GNU General Public License version 2 as published by
     * the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful, but WITHOUT
     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     * more details.
     *
     * You should have received a copy of the GNU General Public License along with
     * this program.  If not, see <http://www.gnu.org/licenses/>.
     */
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <libdce.h>
    #include <xf86drm.h>
    #include <omap_drm.h>
    #include <omap_drmif.h>
    #include <signal.h>
    #include <unistd.h>
    
    #include <pthread.h>
    
    #include "util.h"
    #include "demux.h"
    
    /* Padding for width as per Codec Requirement (for h264) */
    #define PADX  32
    /* Padding for height as per Codec requirement (for h264)*/
    #define PADY  24
    /* Padding for height as per Codec requirement (for MPEG4)*/
    #define PADY_MPEG4  32
    /* omap drm device handle */
    struct omap_device *dev = NULL;
    
    struct decoder {
    	struct display *disp;
    	struct demux *demux;
    	struct buffer *framebuf;
    	Engine_Handle engine;
    	VIDDEC3_Handle codec;
    	VIDDEC3_Params *params;
    	VIDDEC3_DynamicParams *dynParams;
    	VIDDEC3_Status *status;
    	XDM2_BufDesc *inBufs;
    	XDM2_BufDesc *outBufs;
    	VIDDEC3_InArgs *inArgs;
    	VIDDEC3_OutArgs *outArgs;
    	char *input;
    	struct omap_bo *input_bo;
    	int input_sz, uv_offset;
    	int padded_width;
    	int padded_height;
    	int num_outBuf;
    	size_t *outBuf_fd;
    	suseconds_t tdisp;
    	int id;
    	struct buffer *lastOutBuf;
    	int outBufsInUseFlag;
    };
    
    
    struct decoder *decoders[8] = {};
    int ndecoders = 0;
    
    /* When true, do not actually call VIDDEC3_process. For benchmarking. */
    static int no_process = 0;
    static int inloop = 0;
    
    /* When true, loop at end of playback. */
    static int loop = 0;
    
    static void
    usage(char *name)
    {
    	MSG("Usage: %s [OPTIONS] INFILE", name);
    	MSG("Test of viddec3 decoder.");
    	MSG("");
    	MSG("viddec3test options:");
    	MSG("\t-h, --help: Print this help and exit.");
    	MSG("\t--loop\tRestart playback at end of stream.");
    	MSG("\t--inloop\tRestart playback at end of stream along with decoder reinitialization.");
    	MSG("\t--no-process\tDo not actually call VIDDEC3_process method. For benchmarking.");
    	MSG("");
    	disp_usage();
    }
    
    static void
    decoder_close(struct decoder *decoder)
    {
    	if(!decoder) return;
    	/* free output buffers allocated by display */
    	if(inloop < 2 && decoder->disp) disp_free_buffers(decoder->disp,decoder->num_outBuf);
    
    	if (decoder->status)         dce_free(decoder->status);
    	if (decoder->params)         dce_free(decoder->params);
    	if (decoder->dynParams)      dce_free(decoder->dynParams);
    	if (decoder->inBufs) {
    		dce_buf_unlock(1, &(decoder->inBufs->descs[0].buf));
    		close(decoder->inBufs->descs[0].buf);
    		dce_free(decoder->inBufs);
    	}
    	if (decoder->outBufs)        dce_free(decoder->outBufs);
    	if (decoder->inArgs)         dce_free(decoder->inArgs);
    	if (decoder->outArgs)        dce_free(decoder->outArgs);
    	if (decoder->codec)          VIDDEC3_delete(decoder->codec);
    	if (decoder->engine)         Engine_close(decoder->engine);
        if (decoder->input_bo)       omap_bo_del(decoder->input_bo);
    	if (decoder->outBuf_fd)	     free(decoder->outBuf_fd);
    	if(inloop < 2) {
    		if (dev)		             dce_deinit(dev);
    		if (decoder->demux)          demux_deinit(decoder->demux);
    		if (decoder->disp)           disp_close(decoder->disp);
    		if(decoder) {
    		  free(decoder);
    		 }
    	}
    }
    
    static struct decoder *
    decoder_open(int argc, char **argv)
    {
    	static struct decoder *decoder = NULL;
    	char *infile = NULL;
    	int i;
    	static int width, height, padded_width, padded_height;
    	Engine_Error ec;
    	XDAS_Int32 err;
        if(inloop < 2) {
    		decoder = calloc(1, sizeof(*decoder));
    		if (!decoder)
    			return NULL;
    
    		MSG("%p: Opening Display..", decoder);
    		decoder->disp = disp_open(argc, argv);
    		if (!decoder->disp)
    			goto usage;
    
    	    /* loop thru args, find input file.. */
    		for (i = 1; i < argc; i++) {
    			int fd;
    			    if (!argv[i]) {
    				    continue;
    			}
    			fd = open(argv[i], 0);
    			if (fd > 0) {
    				infile = argv[i];
    				argv[i] = NULL;
    				close(fd);
    				break;
    			}
    			break;
    		}
    		if (check_args(argc, argv) || !infile)
    			goto usage;
    		MSG("%p: Opening Demuxer..", decoder);
    		decoder->demux = demux_init(infile, &width, &height);
    		if (!decoder->demux) {
    			ERROR("%p: could not open demuxer", decoder);
    			goto fail;
    		}
    		MSG("%p: infile=%s, width=%d, height=%d", decoder, infile, width, height);
    
    		/* calculate output buffer parameters: */
    		width  = ALIGN2 (width, 4);        /* round up to macroblocks */
    		height = ALIGN2 (height, 4);       /* round up to macroblocks */
    		if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
    			padded_width = width;
    			padded_height= height;
    		} else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
    			padded_width  = ALIGN2 (width + PADX, 7);
    			padded_height = height + PADY_MPEG4;
    		} else {
    			padded_width  = ALIGN2 (width + (2*PADX), 7);
    			padded_height = height + 4*PADY;
    		}
    		decoder->num_outBuf   = MIN(16, 32768 / ((width/16) * (height/16))) + 3;
    		decoder->padded_width = padded_width;
    		decoder->padded_height = padded_height;
    		MSG("%p: padded_width=%d, padded_height=%d, num_buffers=%d",
    			decoder, padded_width, padded_height, decoder->num_outBuf);
    		dce_set_fd(decoder->disp->fd);
    		dev = dce_init();
    		if(dev == NULL) {
    			ERROR("%p: dce init failed", dev);
    			goto fail;
    		}
    		decoder->framebuf = disp_get_fb(decoder->disp);
    		if (! disp_get_vid_buffers(decoder->disp, decoder->num_outBuf,
    				FOURCC_STR("NV12"), decoder->padded_width, decoder->padded_height)) {
    			ERROR("%p: could not allocate buffers", decoder);
    			goto fail;
    		}
    		if(inloop) inloop = 2; /*Don't bother about looping if not asked to*/
        }
    
    	if (!decoder->disp->multiplanar) {
    		decoder->uv_offset = padded_width * padded_height;
    		decoder->outBuf_fd = malloc(sizeof(int)*decoder->num_outBuf);
    		MSG("%p: uv_offset=%d", decoder, decoder->uv_offset);
    	}
    	else{
    		decoder->outBuf_fd = malloc(sizeof(int)*(decoder->num_outBuf*2));
    	}
    
    	decoder->input_sz = width * height;
    	decoder->input_bo = omap_bo_new(decoder->disp->dev,
    			decoder->input_sz, OMAP_BO_WC);
    	decoder->input = omap_bo_map(decoder->input_bo);
    
    
    
    	MSG("%p: Opening Engine..", decoder);
    	decoder->engine = Engine_open("ivahd_vidsvr", NULL, &ec);
    	if (!decoder->engine) {
    		ERROR("%p: could not open engine", decoder);
    		goto fail;
    	}
    
    	decoder->params = dce_alloc(sizeof(IVIDDEC3_Params));
    	decoder->params->size = sizeof(IVIDDEC3_Params);
    
    	decoder->params->maxWidth         = 1920;
    	decoder->params->maxHeight        = 1088;
    	decoder->params->maxFrameRate     = 30000;
    	decoder->params->maxBitRate       = 10000000;
    	decoder->params->dataEndianness   = XDM_BYTE;
    	decoder->params->forceChromaFormat= XDM_YUV_420SP;
    	decoder->params->operatingMode    = IVIDEO_DECODE_ONLY;
    	decoder->params->displayDelay     = IVIDDEC3_DISPLAY_DELAY_AUTO;
    	decoder->params->displayBufsMode  = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
    	MSG("displayBufsMode: %d", decoder->params->displayBufsMode);
    	decoder->params->inputDataMode    = IVIDEO_ENTIREFRAME;
    	decoder->params->metadataType[0]  = IVIDEO_METADATAPLANE_NONE;
    	decoder->params->metadataType[1]  = IVIDEO_METADATAPLANE_NONE;
    	decoder->params->metadataType[2]  = IVIDEO_METADATAPLANE_NONE;
    	decoder->params->numInputDataUnits= 0;
    	decoder->params->outputDataMode   = IVIDEO_ENTIREFRAME;
    	decoder->params->numOutputDataUnits = 0;
    	decoder->params->errorInfoMode    = IVIDEO_ERRORINFO_OFF;
    
    	if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
                decoder->codec = VIDDEC3_create(decoder->engine,
                                            "ivahd_mpeg2vdec", decoder->params);
            }
            else if (decoder->demux->cc->codec_id == AV_CODEC_ID_H264) {
                decoder->codec = VIDDEC3_create(decoder->engine,
                                            "ivahd_h264dec", decoder->params);
            }
    	else if (decoder->demux->cc->codec_id == AV_CODEC_ID_MPEG4) {
    		decoder->demux->first_in_buff = 1;
    		decoder->codec = VIDDEC3_create(decoder->engine,
                                            "ivahd_mpeg4dec", decoder->params);
    	}
    
    	if (!decoder->codec) {
    		ERROR("%p: could not create codec", decoder);
    		goto fail;
    	}
    
    	decoder->dynParams = dce_alloc(sizeof(IVIDDEC3_DynamicParams));
    	decoder->dynParams->size = sizeof(IVIDDEC3_DynamicParams);
    
    	decoder->dynParams->decodeHeader  = XDM_PARSE_HEADER;
    
    	/*Not Supported: Set default*/
    	decoder->dynParams->displayWidth  = 0;
    	decoder->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
    	decoder->dynParams->newFrameFlag  = XDAS_TRUE;
    
    	decoder->status = dce_alloc(sizeof(IVIDDEC3_Status));
    	decoder->status->size = sizeof(IVIDDEC3_Status);
    
    	err = VIDDEC3_control(decoder->codec, XDM_SETPARAMS,
    			decoder->dynParams, decoder->status);
    	if (err) {
    		ERROR("%p: fail: %d", decoder, err);
    		goto fail;
    	}
            decoder->inBufs = dce_alloc(sizeof(XDM2_BufDesc));
    	decoder->inBufs->numBufs = 1;
    	decoder->inBufs->descs[0].buf =	(XDAS_Int8 *)omap_bo_dmabuf(decoder->input_bo);
    	dce_buf_lock(1, &(decoder->inBufs->descs[0].buf));
    	decoder->inBufs->descs[0].bufSize.bytes = omap_bo_size(decoder->input_bo);
    	decoder->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
    
    
    	decoder->outBufs = dce_alloc(sizeof(XDM2_BufDesc));
    	decoder->outBufs->numBufs = 2;
    	decoder->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
    	decoder->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
    
    	decoder->inArgs = dce_alloc(sizeof(IVIDDEC3_InArgs));
    	decoder->inArgs->size = sizeof(IVIDDEC3_InArgs);
    
    	decoder->outArgs = dce_alloc(sizeof(IVIDDEC3_OutArgs));
    	decoder->outArgs->size = sizeof(IVIDDEC3_OutArgs);
    
    
    {
    	
    	XDM2_BufDesc *inBufs = decoder->inBufs;
    	XDM2_BufDesc *outBufs = decoder->outBufs;
    	VIDDEC3_InArgs *inArgs = decoder->inArgs;
    	VIDDEC3_OutArgs *outArgs = decoder->outArgs;
    	int i, n;
    	struct buffer *buf;
    
    	n = demux_read(decoder->demux, decoder->input, decoder->input_sz);
    	MSG("Bytes read %d\n", n);
    	inBufs->descs[0].bufSize.bytes = n;
    	inArgs->numBytes = n;
    
    	buf = disp_get_vid_buffer(decoder->disp);
    	inArgs->inputID = (XDAS_Int32)buf;
    	outBufs->descs[0].buf = buf->fd[0];
    	outBufs->descs[1].buf = (buf->multiplanar) ?buf->fd[1]:(XDAS_Int8 *)((outBufs->descs[0].buf));
    
    	if(buf->multiplanar){
    		decoder->outBuf_fd[0] = buf->fd[0];
    		decoder->outBuf_fd[1] = buf->fd[1];
    		dce_buf_lock(2,decoder->outBuf_fd);
    	}
    	else{
    		decoder->outBuf_fd[0] = buf->fd[0];
    		dce_buf_lock(1,decoder->outBuf_fd);
    	}
    	decoder->outBufs->descs[0].bufSize.bytes =decoder->padded_width*decoder->padded_height;
    	decoder->outBufs->descs[1].bufSize.bytes = decoder->padded_width* (decoder->padded_height/2);
    
    	err = VIDDEC3_process(decoder->codec, inBufs, outBufs, inArgs, outArgs);
    	err = VIDDEC3_control(decoder->codec, XDM_GETSTATUS,
    			decoder->dynParams, decoder->status);
    
    	MSG("outwidth %d outheight %d\n", decoder->status->outputWidth, decoder->status->outputHeight);
    
    }
    	/* not entirely sure why we need to call this here.. just copying omx.. */
    	err = VIDDEC3_control(decoder->codec, XDM_GETBUFINFO,
    			decoder->dynParams, decoder->status);
    	if (err) {
    		ERROR("%p: fail: %d", decoder, err);
    		goto fail;
    	}
    
    		decoder->outBufsInUseFlag = XDAS_FALSE;
    
    	decoder->tdisp = mark(NULL);
    
    	return decoder;
    
    usage:
    	usage(argv[0]);
    fail:
    	if(inloop) inloop = 1; /*Error case: delete everything*/
    	if (decoder)
    		decoder_close(decoder);
    	return NULL;
    }
    
    
    
    /* Returns 1 (true) if the mutex is unlocked, which is the
     * thread's signal to terminate.
      */
    
    pthread_mutex_t mtx;
    
    int needQuit()
     {
       switch(pthread_mutex_trylock(&mtx)) {
        case 0: /* if we got the lock, unlock and return 1 (true) */
    	      pthread_mutex_unlock(&mtx);
              return 1;
        case EBUSY: /* return 0 (false) if the mutex was locked */
    	      return 0;
       }
      return 1;
      }
    
    
    
    
    static void sig_handler(int signo)
    {
      if (signo == SIGINT) {
    	  int i=0;
    	  pthread_mutex_unlock(&mtx);
    	  sleep(1);
    	  exit(0);
      }
    }
    
    
    int
    main(int argc, char **argv)
    {
    
       int i, first = 0;
    
       struct sigaction sa;
    
       sa.sa_handler = sig_handler;
       sigemptyset(&sa.sa_mask);
       sa.sa_flags = 0;
    
       if (sigaction(SIGINT, &sa, NULL) == -1) {
         ERROR ("\nDid not catch  SIGINT\n");
       }
       signal(SIGINT,sig_handler);
    
       pthread_mutex_init(&mtx,NULL);
       pthread_mutex_lock(&mtx);
    
        for (i = 1; i < argc; i++) {
    		if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
    			usage(argv[0]);
    			exit(0);
    
    		} else if (!strcmp(argv[i], "--loop")) {
    			loop = 1;
    			argv[i] = NULL;
    
    		} else if (!strcmp(argv[i], "--no-process")) {
    			no_process = 1;
    			argv[i] = NULL;
    
    		} else if (!strcmp(argv[i], "--inloop")) {
    			inloop = 1; // this means inloop is detected
    			DBG("detected inloop = %d\n", inloop);
    			loop = 1; //we want rewind as well
    			argv[i] = NULL;
    		} else if (!strcmp(argv[i], "--")) {
    			argv[first] = argv[0];
    			decoders[ndecoders] = decoder_open(i - first, &argv[first]);
    			decoders[ndecoders]->id = ndecoders;
    			ndecoders++;
    			first = i;
    		}
    	}
    
    	argv[first] = argv[0];
    	argc = i - first;
    	if(ndecoders) {
    	    decoders[ndecoders] = decoder_open(argc ,&argv[first]);
    		decoders[ndecoders]->id = ndecoders;
    		ndecoders++;
    	}
    
    	 {
    		int itr = 0;
    		do {
    			decoders[0] = decoder_open(argc, &argv[first]);
    			decoders[0]->id = 0;
    			ndecoders++;
    			decoder_close(decoders[0]);
    			if (inloop) {
    				MSG("=================Iteration %d complete =============== %d\n", ++itr);
    			}
    		}while(inloop);
    	}
    	return 0;
    }
    

    Can you check what is missing?

    Ram

  • Hi ram,
    Maybe the whole input frame is ok, but using input stream I metioned above wil be error.
    thank you, I will try with the whole input frame.
  • Hi ram,
    can you dump the first input buffer, i want to check the stream format. thank you
  • Hi Gao,
    Does your target filesystem has the stream HistoryOfTI-480p.m4v in /usr/share/ti/video?

    This is an elementary stream with no container data. Frame size of first frame is 3278 bytes
    Ram
  • Hi ram,
    I cannot find this media file, can you send it or show me uri to download?
  • I already got this media file.
  • Hi Ram,
    in viddec3test , width and height is already parsed by demuxer before calling XDM_GETSTATUS
    I wonder how to parse w/h from stream without knowing the w/h before.

    =========================
    decoder->demux = demux_init(infile, &width, &height);
    if (!decoder->demux) {
    ERROR("%p: could not open demuxer", decoder);
    goto fail;
    }
  • Hi Gao,
    Yes, it is parsed but I am not informing this to decoder. I am using demuxer here to get one frame of data.
    I am not passing width and height to decoder's paramters , I have set maxWidth and maxHeight to 1920x1080