Intel® Integrated Performance Primitives
Deliberate problems developing high-performance vision, signal, security, and storage applications.

Splitting and muxing video

ulisses87
Beginner
353 Views

Hello,

I need to read MP4 file, analyze it, cut some parts and write modified file again with the same coding parameters as source file. I have the problem with the basic read/write file module.

My problems:

1.) Is it good solution of my problem? Currently this function is processing my file by 50% of real duration of video (e.g if video lasts 2 minutes, it works 1 minute). Can I do this faster?

2.) Some blocks of code are repeated in second while, where I flush data from buffer. How I can solve this problem?

3.) The output file does not have exactly the same parameters as source file (please take a look to screenshots from Media Info

4.) I don't need to write output stream to output yuv file. How I can disable thic functionality? I tried to replace FWVideoRender with NullVideoRender, but it doesn't work. I think I did sth wrong.

5.) How I can rewrite audio stream from input to destination video file? In the same way as video stream?

Basing on splitter and muxer samples from Intel, I wrote this code:

Thanks for any help or tips.

[cpp]void MainModule(vm_char *inputfilename, vm_char *outputfilename, bool saveimage){
	Ipp32u videoTrack=0;

	int exit_flag =0;

	UMC::Status status;

	UMC::Status status2;

	UMC::Status status3;

	UMC::MediaData in; 

	UMC::VideoData out;

	UMC::FIOReader reader; 

	UMC::FileReaderParams readerParams;

	UMC::SplitterParams splitterParams;

	UMC::SplitterInfo * streamInfo;

	UMC::MP4Splitter Splitter;
		
	UMC::VideoStreamInfo *videoInfo=NULL;

	UMC::VideoDecoder *  videoDecoder;

	UMC::VideoDecoderParams videoDecParams;

	UMC::FWVideoRender fwRender;

	UMC::FWVideoRenderParams fwRenderParams;

	//UMC::NULLVideoRender fwRender;

	IppiSize imgSize; 

	IppStatus result; 

	int arrSize; 

	char name[200]="output "; 

	int i=0; 

	char number[20]; 

	const Ipp8u* dst[3]; 

	CIppImage jpeg; 
	
	readerParams.m_portion_size = 0;

	vm_string_strcpy(readerParams.m_file_name, inputfilename); 

	if((status = reader.Init(&readerParams))!= UMC::UMC_OK) 
       return;

	splitterParams.m_lFlags = UMC::VIDEO_SPLITTER; 

	splitterParams.m_pDataReader = &reader; 

    if((status = Splitter.Init(splitterParams))!= UMC::UMC_OK) 
	   return;

	Splitter.GetInfo(&streamInfo); 

    for (videoTrack = 0; videoTrack <  streamInfo->m_nOfTracks; videoTrack++) { 
      if (streamInfo->m_ppTrackInfo[videoTrack]->m_Type == UMC::TRACK_H264) 
           break;
    }

	videoInfo = (UMC::VideoStreamInfo*)(streamInfo->m_ppTrackInfo[videoTrack]->m_pStreamInfo); 

	if(videoInfo->stream_type!=UMC::H264_VIDEO) 
        return;

    videoDecParams.info =  (*videoInfo);

	videoDecParams.m_pData = streamInfo->m_ppTrackInfo[videoTrack]->m_pDecSpecInfo;

	videoDecParams.numThreads = 1; 

    videoDecoder = (UMC::VideoDecoder*)(new UMC::H264VideoDecoder());

	if((status = videoDecoder->Init(&videoDecParams))!= UMC::UMC_OK) 
		return;

	fwRenderParams.out_data_template.Init(
		videoInfo->clip_info.width, 
		videoInfo->clip_info.height, 
		videoInfo->color_format);

    //fwRenderParams.pOutFile = outputfilename; 

    if(status = fwRender.Init(&fwRenderParams)!= UMC::UMC_OK)
		return;

	imgSize.height=videoInfo->clip_info.height; 

	imgSize.width=videoInfo->clip_info.width; 

	arrSize=imgSize.width * imgSize.height * 3; 

	unsigned char* rgbBuff=(unsigned char*)malloc(arrSize);

	unsigned char* grayBuff=(unsigned char*)malloc(imgSize.width * imgSize.height);

	dst[0] = (Ipp8u*)malloc(imgSize.width * imgSize.height); 
	dst[1] = (Ipp8u*)malloc(imgSize.width * imgSize.height);
	dst[2] = (Ipp8u*)malloc(imgSize.width * imgSize.height); 

	//MUXER

    UMC::MediaData  DataOut;  
	UMC::MediaData MuxData; 

	UMC::VideoData DataIn;  

    UMC::H264EncoderParams Params; 

	UMC::H264VideoEncoder H264Encoder; 

	UMC::MP4Muxer Muxer; 

	UMC::MuxerParams MuxerParams;

    Ipp8u *cMaxVideoData = NULL;

	int FrameSize; 
       
    UMC::FileWriter Writer; 

	UMC::FileWriterParams WriterParams; 

    vm_string_strcpy(WriterParams.m_file_name, outputfilename);  

    Writer.Init(&WriterParams);   
  
    MuxerParams.m_lpDataWriter = &Writer;  

	MuxerParams.m_SystemType = streamInfo->m_SystemType; 

    MuxerParams.m_nNumberOfTracks = 1; 

    MuxerParams.pTrackParams = new UMC::TrackParams[MuxerParams.m_nNumberOfTracks];  
    
    MuxerParams.pTrackParams[0].type = UMC::VIDEO_TRACK; 

    MuxerParams.pTrackParams[0].info.video = videoInfo;

    MuxerParams.pTrackParams[0].bufferParams.m_prefInputBufferSize=2000000;

    MuxerParams.pTrackParams[0].bufferParams.m_prefOutputBufferSize=2000000;  
  
    if((status =Muxer.Init(&MuxerParams))!=UMC::UMC_OK)  
      return;   
     
    Params.info.clip_info.height=videoInfo->clip_info.height; 

    Params.info.clip_info.width=videoInfo->clip_info.width; 

    Params.info.bitrate = videoInfo->bitrate;

    Params.numThreads = 1; 

    if((status = H264Encoder.Init(&Params))!=UMC::UMC_OK)
      return;   
    
	FrameSize = videoInfo->clip_info.height * videoInfo->clip_info.width * 3/2; 

    cMaxVideoData= ippsMalloc_8u(MAXAFRAMESIZE); //max wielkosc klatki

    DataIn.Init(videoInfo->clip_info.width,videoInfo->clip_info.height,UMC::YV12,8); 

	Splitter.Run(); 

	do{   
		do{ 
			if (in.GetDataSize() < 4){
	    		do{ 
					status= Splitter.GetNextData(&in,videoTrack);
					if(status==UMC::UMC_ERR_NOT_ENOUGH_DATA)
   			            vm_time_sleep(5);
				}while(status==UMC::UMC_ERR_NOT_ENOUGH_DATA);

			    if(((status != UMC::UMC_OK) && (status != UMC::UMC_ERR_END_OF_STREAM))||
				(status == UMC::UMC_ERR_END_OF_STREAM)&& (in.GetDataSize()<4)) {
                     exit_flag=1;
				}
			}

			fwRender.LockInputBuffer(&out); 

		    status2=videoDecoder->GetFrame(&in,&out); 

			if(status2==UMC::UMC_OK){

				dst[0] = (Ipp8u*)out.GetPlanePointer(0);

				dst[1] = (Ipp8u*)out.GetPlanePointer(1); 

				dst[2] = (Ipp8u*)out.GetPlanePointer(2);
			
				result = ippiYUV420ToRGB_8u_P3C3(dst,rgbBuff,imgSize); 

				if(result != ippStsNoErr){ 
					return;
				}

				ippiRGBToGray_8u_C3C1R(rgbBuff,imgSize.width*3,grayBuff,imgSize.width,imgSize); 

				strcpy(name,"output "); 

				itoa(i,number,10); 

				strcat(name,number);
			
				strcat(name,".jpg");
			
				jpeg.Attach(imgSize.width,imgSize.height,1,8,grayBuff,imgSize.width);

				jpeg.Color(JC_GRAY); 

				if(true==saveimage){
					SaveJPEG(name,jpeg,JC_GRAY); 
				}

				i++; 

				DataIn.SetBufferPointer((Ipp8u*)out.GetDataPointer(),FrameSize);

				DataIn.SetDataSize(FrameSize); 

				DataOut.SetBufferPointer(cMaxVideoData,MAXAFRAMESIZE);

				status3 = H264Encoder.GetFrame(&DataIn, &DataOut);

				if(status3 == UMC::UMC_OK){

					MuxData.SetBufferPointer((Ipp8u*)DataOut.GetBufferPointer(),DataOut.GetDataSize());  

					memcpy(MuxData.GetDataPointer(),DataOut.GetDataPointer(), DataOut.GetDataSize()); 

					MuxData.SetDataSize(DataOut.GetDataSize());  

					MuxData.SetTime(i*((double)1.0)/25);

					do {  
						status3 = Muxer.PutVideoData(&MuxData); 

						if (UMC::UMC_ERR_NOT_ENOUGH_BUFFER == status3) 
							vm_time_sleep(5);  

					}while (UMC::UMC_ERR_NOT_ENOUGH_BUFFER == status3);

					DataIn.SetBufferPointer((Ipp8u*)out.GetDataPointer(),FrameSize); 
					DataIn.SetDataSize(FrameSize); 

					DataOut.SetBufferPointer(cMaxVideoData,MAXAFRAMESIZE);  
				}
			 }

    	  	 fwRender.UnLockInputBuffer(&out); 

		     fwRender.RenderFrame(); 

	     }while(!exit_flag && (status == UMC::UMC_ERR_NOT_ENOUGH_DATA || status == UMC::UMC_ERR_SYNC));
	 }while (exit_flag!=1);

	do{    
         fwRender.LockInputBuffer(&out); 

         status  = videoDecoder->GetFrame(NULL,&out); 
		 
		 if(status==UMC::UMC_OK){ 

			dst[0] = (Ipp8u*)out.GetPlanePointer(0); 
			dst[1] = (Ipp8u*)out.GetPlanePointer(1); 
			dst[2] = (Ipp8u*)out.GetPlanePointer(2); 
			
			result = ippiYUV420ToRGB_8u_P3C3(dst,rgbBuff,imgSize); 

			if(result != ippStsNoErr){ 
				return;
			}

			ippiRGBToGray_8u_C3C1R(rgbBuff,imgSize.width*3,grayBuff,imgSize.width,imgSize); 
				
			strcpy(name,"output "); 
				
			itoa(i,number,10);
				
			strcat(name,".jpg"); 
				
			jpeg.Attach(imgSize.width,imgSize.height,1,8,grayBuff,imgSize.width);

			jpeg.Color(JC_GRAY);

			if(true == saveimage){
				SaveJPEG(name,jpeg,JC_GRAY);
			}

			i++; 

			DataIn.SetBufferPointer((Ipp8u*)out.GetDataPointer(),FrameSize); 

			DataIn.SetDataSize(FrameSize); 

			DataOut.SetBufferPointer(cMaxVideoData,MAXAFRAMESIZE);

			status3 = H264Encoder.GetFrame(&DataIn, &DataOut);

			if(status3 == UMC::UMC_OK){

				MuxData.SetBufferPointer((Ipp8u*)DataOut.GetBufferPointer(),DataOut.GetDataSize());

				memcpy(MuxData.GetDataPointer(),DataOut.GetDataPointer(), DataOut.GetDataSize());

				MuxData.SetDataSize(DataOut.GetDataSize());

				MuxData.SetTime(i*((double)1.0)/25);

				do {  
					status3 = Muxer.PutVideoData(&MuxData); 

					if (UMC::UMC_ERR_NOT_ENOUGH_BUFFER == status3) 
						vm_time_sleep(5);  

				}while (UMC::UMC_ERR_NOT_ENOUGH_BUFFER == status3);              

				DataIn.SetBufferPointer((Ipp8u*)out.GetDataPointer(),FrameSize);
				DataIn.SetDataSize(FrameSize);

				DataOut.SetBufferPointer(cMaxVideoData,MAXAFRAMESIZE);
			}
		 }

         fwRender.UnLockInputBuffer(&out);

         fwRender.RenderFrame();

    }while(status == UMC::UMC_OK);

	Muxer.Close();

}[/cpp]

0 Kudos
3 Replies
ulisses87
Beginner
353 Views

Nobody can help me?

0 Kudos
Sergey_O_Intel1
Employee
353 Views
Hi.
Your usage model is widespread.
What you're really doing is called transcoding with some preprocessing. You split, decode, perform color conversion (or other conversion), encode and then multiplex. Currently you've got performance of 0.5realtime and it can hardly be faster in your case.
Parameters of output video clip can not stay the same because Encoder is different. Try to transcode your output once more and parameters will be the same.
Render is used if one wants to render the output or to dump it to a file. You may simply use Sample Buffer instead.
Concerning audio you may simply demultiplex it and multiplex back without transcoding.
Regards
-Sergey
0 Kudos
ulisses87
Beginner
353 Views

Hi,

Thank you for your reply. The problem is that I need to split my video file to smaller parts and to merge its again WITHOUT transcoding and preprocessing (something like MP4Box or AviDemux tools). This process is quicker than transcoding with preprocessing. Of course I want to cut on I-frames (I simply want to cut off detected commercials). I it isnt' possible with IPP, I have decided to use external software.

Now my main and I hope the last problem is using of SampleBufferClass, which you advised me. As I said before - I don't want to write processed video file to YUV external file.

I read documentation carefully and tried to use SampleBuffer instead of fwRender (even name is not changed) in this way (only part of code - whole sampe is based os example from Intel webpage):

[bash]
UMC::SampleBuffer fwRender;
UMC::MediaBufferParams fwRenderParams;
fwRenderParams.m_numberOfFrames = 3;
fwRenderParams.m_prefInputBufferSize = 1024;
fwRenderParams.m_prefOutputBufferSize = 0;

	do{
		do{ 
			if (in.GetDataSize() < 4){
	    		do{ 
					status= Splitter.GetNextData(&in,videoTrack);
					//LOG(WARNING) << IntToStr(status);
					if(status==UMC::UMC_ERR_NOT_ENOUGH_DATA){
   			            vm_time_sleep(5);
					}
				}while(status==UMC::UMC_ERR_NOT_ENOUGH_DATA);

			    if(((status != UMC::UMC_OK) && (status != UMC::UMC_ERR_END_OF_STREAM))||
				(status == UMC::UMC_ERR_END_OF_STREAM)&& (in.GetDataSize()<4)) {
                     exit_flag=1;
				}
			}

			fwRender.LockInputBuffer(&out); 

		    status2=videoDecoder->GetFrame(&in,&out);

			LOG(WARNING) << IntToStr(status2);


			if(status2 == UMC::UMC_OK){ 

				dst[0] = (Ipp8u*)out.GetPlanePointer(0); 
				dst[1] = (Ipp8u*)out.GetPlanePointer(1); 
				dst[2] = (Ipp8u*)out.GetPlanePointer(2); 
			
				result = ippiYUV420ToRGB_8u_P3C3(dst,rgbBuff,imgSize);

				if(result != ippStsNoErr){ 
					return;
				}

				ippiRGBToGray_8u_C3C1R(rgbBuff,imgSize.width*3,grayBuff,imgSize.width,imgSize); 
				Apply_TVN_Detection_HaarLikeFeature(grayBuff, imgSize.width, in.GetTime(),i);

				i++;
			 }
			
    	  	 fwRender.UnLockInputBuffer(&out);

	     }while(!exit_flag && (status == UMC::UMC_ERR_NOT_ENOUGH_DATA || status == UMC::UMC_ERR_SYNC));
	 }while (exit_flag!=1);

	do{    
         fwRender.LockInputBuffer(&out);

         status  = videoDecoder->GetFrame(NULL,&out);
		 
		 if(status==UMC::UMC_OK){

			dst[0] = (Ipp8u*)out.GetPlanePointer(0); //pobranie wartoci Y (?)
			dst[1] = (Ipp8u*)out.GetPlanePointer(1); //pobranie wartoci U (?)
			dst[2] = (Ipp8u*)out.GetPlanePointer(2); //pobranie wartoci V (?)
			
			result = ippiYUV420ToRGB_8u_P3C3(dst,rgbBuff,imgSize); /

			if(result != ippStsNoErr){
				return;
			}

			ippiRGBToGray_8u_C3C1R(rgbBuff,imgSize.width*3,grayBuff,imgSize.width,imgSize);
			
			Apply_TVN_Detection_HaarLikeFeature(grayBuff, imgSize.width, in.GetTime(),i);

			i++;
		 }

         fwRender.UnLockInputBuffer(&out);

	}while(status == UMC::UMC_OK);[/bash]
Unfortunately in line number 31, after calling GetFrame method, I have error -996 (VM_NOT_ENOUGH_DATA) and main loop is infinity. What's more I can't get next frames... I suppose that I need to do something manually, what was automated earlier by fwRender, but I don't know what is it.

Could you help me?

0 Kudos
Reply