PageRenderTime 181ms CodeModel.GetById 104ms app.highlight 54ms RepoModel.GetById 16ms app.codeStats 1ms

/Avidemux/avidemux/ADM_outputs/oplug_mpegFF/oplug_vcdff.cpp

http://mulder.googlecode.com/
C++ | 560 lines | 441 code | 79 blank | 40 comment | 88 complexity | b71049e535686c42b815849068434dd2 MD5 | raw file
  1/***************************************************************************
  2                          oplug_vcdff.cpp  -  description
  3                             -------------------
  4    begin                : Sun Nov 10 2002
  5    copyright            : (C) 2002 by mean
  6    email                : fixounet@free.fr
  7    
  8    Ouput using FFmpeg mpeg1 encoder
  9    Much faster than mjpegtools, albeit quality seems inferior
 10    
 11 ***************************************************************************/
 12
 13/***************************************************************************
 14 *                                                                         *
 15 *   This program is free software; you can redistribute it and/or modify  *
 16 *   it under the terms of the GNU General Public License as published by  *
 17 *   the Free Software Foundation; either version 2 of the License, or     *
 18 *   (at your option) any later version.                                   *
 19 *                                                                         *
 20 ***************************************************************************/
 21#define __STDC_LIMIT_MACROS

 22#include "config.h"

 23
 24#ifdef USE_FFMPEG

 25#include "ADM_default.h"

 26#include "ADM_threads.h"

 27
 28extern "C" {
 29#include "ADM_lavcodec.h"

 30}
 31
 32#include "avi_vars.h"

 33#include "DIA_coreToolkit.h"

 34
 35#include "ADM_encoder/ADM_vidEncode.hxx"

 36#include "ADM_encoder/adm_encoder.h"

 37
 38#include "../oplug_mpegFF/oplug_vcdff.h"

 39
 40#include "ADM_userInterfaces/ADM_commonUI/DIA_encoding.h"

 41#include "ADM_audiofilter/audioprocess.hxx"

 42#include "ADM_audiofilter/audioeng_buildfilters.h"

 43#include "../ADM_lavformat.h"

 44
 45#include "ADM_encoder/adm_encConfig.h"

 46#include "ADM_libraries/ADM_mplex/ADM_mthread.h"

 47
 48static uint8_t *_buffer = NULL, *_outbuffer = NULL;
 49static void end(void);
 50extern const char *getStrFromAudioCodec(uint32_t codec);
 51
 52extern SelectCodecType videoCodecGetType(void);
 53
 54static char *twoPass = NULL;
 55static char *twoFake = NULL;
 56
 57ps_muxer psMuxerConfig = {PS_MUXER_DVD, 0};
 58
 59uint8_t oplug_mpegff(const char *name, ADM_OUT_FORMAT type)
 60{
 61AVDMGenericVideoStream *_incoming;
 62Encoder  *encoder=NULL;
 63ADMMpegMuxer	*muxer=NULL;
 64FILE 		*file=NULL;
 65uint8_t		audioBuffer[48000];
 66uint32_t	audioLen=0;
 67uint32_t _w,_h,_fps1000,_page,total;	
 68AVDMGenericAudioStream	*audio=NULL;
 69uint32_t len,flags;
 70uint32_t size;
 71ADM_MUXER_TYPE mux;
 72uint32_t  audio_encoding=0;
 73uint32_t  real_framenum=0;
 74uint8_t   ret=0;
 75uint32_t  sample_target=0;
 76uint32_t  total_sample=0;
 77ADMBitstream bitstream(0);
 78uint32_t audioSum=0;
 79DIA_encoding  *encoding = NULL;
 80int reuse = 0;
 81int r = 0;
 82int frameDelay = 0;
 83
 84        twoPass=new char[strlen(name)+6];
 85        twoFake=new char[strlen(name)+6];
 86  
 87        strcpy(twoPass,name);
 88        strcat(twoPass,".stat");
 89        strcpy(twoFake,name);
 90        strcat(twoFake,".fake");
 91 
 92        _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
 93        _w=_incoming->getInfo()->width;
 94        _h=_incoming->getInfo()->height;
 95        _fps1000=_incoming->getInfo()->fps1000;
 96        _page=_w*_h;
 97        _page+=_page>>1;
 98
 99        total=_incoming->getInfo()->nb_frames;
100        if(!total) return 0;	
101        
102        switch(type)
103        {
104            default:
105                    ADM_assert(0);
106            case ADM_ES:
107                        // Else open file (if possible)                       
108                        mux=MUXER_NONE;
109                        break;
110            case ADM_TS:
111                    if(!currentaudiostream)
112                    {
113                      GUI_Error_HIG(QT_TR_NOOP("There is no audio track"), NULL);
114					  goto finishvcdff;
115                    }
116                    audio=mpt_getAudioStream();
117                    mux=MUXER_TS;
118                    break;
119            case ADM_PS:
120            
121            {
122                if(!currentaudiostream)
123                {
124                  GUI_Error_HIG(QT_TR_NOOP("There is no audio track"), NULL);
125				  goto finishvcdff;
126                }
127                audio=mpt_getAudioStream();
128                // Have to check the type
129                // If it is mpeg2 we use DVD-PS
130                // If it is mpeg1 we use VCD-PS
131                // Later check if it is SVCD
132                if(!audio)
133                {
134                  GUI_Error_HIG(QT_TR_NOOP("Audio track is not suitable"), NULL);
135				  goto finishvcdff;
136                }
137                // Check
138                WAVHeader *hdr=audio->getInfo();	
139                audio_encoding=hdr->encoding;
140
141				switch (psMuxerConfig.muxingType)
142				{
143					case PS_MUXER_VCD:
144					{
145						if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 44100 || hdr->encoding != WAV_MP2))
146						{
147							GUI_Error_HIG(("Incompatible audio"),QT_TR_NOOP( "For VCD, audio must be 44.1 kHz MP2."));
148							goto finishvcdff;
149						}
150
151						mux = MUXER_VCD;
152						printf("X*CD: Using VCD PS\n");
153						break;
154					}
155					case PS_MUXER_SVCD:
156					{
157						if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 44100 && hdr->encoding == WAV_MP2))
158						{
159							GUI_Error_HIG(("Incompatible audio"),QT_TR_NOOP( "For SVCD, audio must be 44.1 kHz MP2."));
160							goto finishvcdff;
161						}
162
163						mux = MUXER_SVCD;
164						printf("X*VCD: Using SVCD PS\n");
165						break;
166					}
167					case PS_MUXER_DVD:
168					{
169						if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 48000 || (hdr->encoding != WAV_MP2 && hdr->encoding != WAV_AC3 && hdr->encoding != WAV_LPCM)))
170						{
171							GUI_Error_HIG(("Incompatible audio"), QT_TR_NOOP("For DVD, audio must be 48 kHz MP2, AC3 or LPCM."));
172							goto finishvcdff;								
173						}
174
175						mux = MUXER_DVD;
176						printf("X*VCD: Using DVD PS\n");
177						break;
178					}
179				}
180            }
181         }
182        // Create muxer
183       encoder = getVideoEncoder(0);
184
185	   if (encoder == NULL)
186		   return 0;
187
188      encoder->setLogFile(twoPass,total);
189
190	  if (encoder->isDualPass())
191	  {
192		  printf("Verifying log file\n");
193
194		  if (encoder->verifyLog(twoPass, total) && GUI_Question(QT_TR_NOOP("Reuse the existing log file?")))
195			  reuse = 1;
196	  }
197
198      if(!encoder->configure(_incoming, reuse))
199              goto finishvcdff;
200
201      _buffer=new uint8_t[_page]; // Might overflow if _page only
202      _outbuffer=new uint8_t[_page];
203
204      ADM_assert(  _buffer);
205      ADM_assert(  _outbuffer);
206
207      encoding =new DIA_encoding(_fps1000);
208      switch (videoCodecGetType())
209      {
210          case CodecRequant:
211            encoding->setCodec(QT_TR_NOOP("MPEG Requantizer"));
212            break;
213          case CodecExternal:
214            encoding->setCodec(encoder->getDisplayName());
215            break;
216          default:
217            ADM_assert(0);
218	}
219        switch(mux)
220          {
221            case MUXER_NONE:encoding->setContainer(QT_TR_NOOP("MPEG ES"));break;
222            case MUXER_TS:  encoding->setContainer(QT_TR_NOOP("MPEG TS"));break;
223            case MUXER_VCD: encoding->setContainer(QT_TR_NOOP("MPEG VCD"));break;
224            case MUXER_SVCD:encoding->setContainer(QT_TR_NOOP("MPEG SVCD"));break;
225            case MUXER_DVD: encoding->setContainer(QT_TR_NOOP("MPEG DVD"));break;
226            default:
227                ADM_assert(0);
228          }
229
230		// pass 1
231		if(encoder->isDualPass()) //Cannot be requant
232		{
233			if (!reuse)
234			{
235				encoding->setPhasis(QT_TR_NOOP("Pass 1/2"));
236				encoder->startPass1();
237
238				bitstream.data = _buffer;
239				bitstream.bufferSize = _page;
240
241				for(uint32_t frame = 0; frame < total; frame++)
242				{
243					if (!encoding->isAlive())
244					{
245						r = 0;
246						break;
247					}
248
249					for (;;)
250					{
251						bitstream.cleanup(frame);
252
253						if (frame + frameDelay >= total)
254						{
255							if (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
256								r = encoder->encode(UINT32_MAX, &bitstream);
257							else
258								r = 0;
259						}
260						else
261							r = encoder->encode(frame + frameDelay, &bitstream);
262
263						if (!r)
264						{
265							printf("Encoding of frame %lu failed!\n", frame);
266							GUI_Error_HIG(QT_TR_NOOP("Error while encoding"), NULL);
267
268							break;
269						}
270
271						if (bitstream.len == 0 && (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
272						{
273							printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
274							frameDelay++;
275						}
276						else
277							break;
278					}
279
280					if (!r)
281						goto finishvcdff;
282
283					encoding->setFrame(frame, bitstream.len, bitstream. out_quantizer, total);
284				}
285			}
286
287			encoder->startPass2();
288			encoding->reset();
289		}
290                
291              switch(type)
292              {
293                case ADM_PS:
294                  muxer=new mplexMuxer;
295                  break;
296                case ADM_TS:
297                  muxer=new tsMuxer;
298                  break;
299                case ADM_ES:
300                  break;
301                default:
302                  ADM_assert(0);
303      
304      
305              }
306              if(muxer)
307              {
308                if(!muxer->open(name,0,mux,avifileinfo,audio->getInfo()))
309                {
310                  printf("Muxer init failed\n");
311				  goto finishvcdff;
312                }
313                double sample_time;
314
315                sample_time=total;
316                sample_time*=1000;
317                sample_time/=_fps1000; // target_time in second
318                sample_time*=audio->getInfo()->frequency;
319                sample_target=(uint32_t)floor(sample_time);
320              }
321              else
322              {
323                file=fopen(name,"wb");
324                if(!file)
325                {
326                  GUI_Error_HIG(QT_TR_NOOP("File error"), QT_TR_NOOP("Cannot open \"%s\" for writing."), name);
327				  goto finishvcdff;
328                }
329              }
330          if(encoder->isDualPass())
331                  encoding->setPhasis (QT_TR_NOOP("Pass 2/2"));
332          else
333                  encoding->setPhasis (QT_TR_NOOP("Encoding"));
334
335         // Set info for audio if any
336         if(muxer)
337         {
338            if(!audioProcessMode())
339                  encoding->setAudioCodec(QT_TR_NOOP("Copy"));
340            else
341                  encoding->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
342         }
343         //**********************************************************
344         //  In that case we do multithreadedwriting (yes!)
345         //**********************************************************
346
347         if(mux==MUXER_DVD || mux==MUXER_SVCD || mux==MUXER_VCD)
348         {
349           pthread_t audioThread,videoThread,muxerThread;
350           muxerMT context;
351           //
352           bitstream.data=_outbuffer;
353           bitstream.bufferSize=_page;
354           // 
355           memset(&context,0,sizeof(context));
356           context.videoEncoder=encoder;
357           context.audioEncoder=audio;
358           context.muxer=(mplexMuxer *)muxer;
359           context.nbVideoFrame=total;
360           context.audioTargetSample=sample_target;
361           context.audioBuffer=audioBuffer;
362           context.bitstream=&bitstream;
363           context.opaque=(void *)encoding;
364
365           // start audio thread
366           ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioSlave,&context)); 
367           ADM_assert(!pthread_create(&videoThread,NULL,(THRINP)defaultVideoSlave,&context)); 
368           while(1)
369           {
370             accessMutex.lock();
371             if(!encoding->isAlive())
372             {
373               context.audioAbort=1;
374               context.videoAbort=1;
375               printf("[mpegFF]Waiting for slaves\n");
376               accessMutex.unlock();
377               while(1)
378               {
379                 accessMutex.lock();
380                 if(context.audioDone && context.videoDone)
381                 {
382                   printf("[mpegFF]Both audio & video done\n");
383                   if(context.audioDone==1 && context.videoDone==1) ret=1;
384                   accessMutex.unlock();
385                   goto finishvcdff;
386                 }
387                 accessMutex.unlock();
388                 ADM_usleep(50000);
389 
390               }
391               
392             }
393             if(context.audioDone==2 || context.videoDone==2 ) //ERROR
394             {
395               context.audioAbort=1;
396               context.videoAbort=1;
397             }
398             if(context.audioDone && context.videoDone)
399             {
400               printf("[mpegFF]Both audio & video done\n");
401               if(context.audioDone==1 && context.videoDone==1) ret=1;
402               accessMutex.unlock();
403               goto finishvcdff;
404             }
405             accessMutex.unlock();
406             ADM_usleep(1000*1000);
407             
408           }
409           
410         }
411         //**********************************************************
412         //  NOT MULTITHREADED
413         //**********************************************************
414
415      bitstream.data=_outbuffer;
416      bitstream.bufferSize=_page;
417	  r = frameDelay = 0;
418
419	  for(uint32_t frame = 0; frame < total; frame++)
420	  {
421		  if (!encoding->isAlive())
422		  {
423			  r = 0;
424			  break;
425		  }
426
427		  for (;;)
428		  {
429			  bitstream.cleanup(frame);
430
431			  if (frame + frameDelay >= total)
432			  {
433				  if (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
434					  r = encoder->encode(UINT32_MAX, &bitstream);
435				  else
436					  r = 0;
437			  }
438			  else
439				  r = encoder->encode(frame + frameDelay, &bitstream);
440
441			  if (!r)
442			  {
443				  printf("Encoding of frame %lu failed!\n", frame);
444				  GUI_Error_HIG(QT_TR_NOOP("Error while encoding"), NULL);
445				  break;
446			  }
447
448			  if (bitstream.len == 0 && (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
449			  {
450				  printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
451				  frameDelay++;
452			  }
453			  else
454				  break;
455		  }
456
457		  if (!r)
458			  goto finishvcdff;
459
460		  if(file)
461		  {
462			  fwrite(_outbuffer,bitstream.len,1,file);
463		  }
464		  else
465		  {
466			  muxer->writeVideoPacket(&bitstream);
467			  real_framenum++;
468
469			  if(total_sample < sample_target)
470			  {
471				  uint32_t samples;
472
473				  while(muxer->needAudio() && total_sample < sample_target) 
474				  {				
475					  if (!audio->getPacket(audioBuffer, &audioLen, &samples))	
476						  break; 
477
478					  if(audioLen) 
479					  {
480						  muxer->writeAudioPacket(audioLen, audioBuffer); 
481						  total_sample += samples;
482						  audioSum += audioLen;
483					  }
484				  }
485			  }
486
487		  }
488
489		  encoding->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
490		  encoding->setAudioSize(audioSum);
491	  }
492
493        ret=1;
494finishvcdff:
495        printf("[MPEGFF] Finishing..\n");
496
497		if (encoding)
498			delete encoding;
499
500        end();
501
502        if(file)
503        {
504                fclose(file);
505                file=NULL;
506        }
507        else if(muxer)
508        {
509                muxer->close();
510                delete muxer;
511                muxer=NULL;
512        }
513
514        delete encoder;
515
516		if (audio)
517			deleteAudioFilter(audio);
518
519        return ret;
520}
521	
522void end (void)
523{
524        
525        delete [] _buffer;
526        delete [] _outbuffer;
527
528        _buffer		=NULL;
529        _outbuffer=NULL;
530        
531        if(twoPass) delete [] twoPass;
532        if(twoFake) delete [] twoFake;
533        
534        twoPass=twoFake=NULL;
535        
536}
537AVDMGenericAudioStream *mpt_getAudioStream (void)
538{
539  AVDMGenericAudioStream *audio = NULL;
540  if (audioProcessMode ())	// else Raw copy mode
541  {
542    if (currentaudiostream->isCompressed ())
543    {
544      if (!currentaudiostream->isDecompressable ())
545      {
546        return NULL;
547      }
548    }
549    audio =  buildAudioFilter (currentaudiostream,  video_body->getTime (frameStart));
550  }
551  else				// copymode
552  {
553      // else prepare the incoming raw stream
554      // audio copy mode here
555    audio = buildAudioFilter (currentaudiostream,video_body->getTime (frameStart));
556  }
557  return audio;
558}
559#endif	

560// EOF