PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/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
Possible License(s): LGPL-2.1, LGPL-2.0, BSD-3-Clause, GPL-2.0, AGPL-1.0, GPL-3.0
  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. Ouput using FFmpeg mpeg1 encoder
  8. Much faster than mjpegtools, albeit quality seems inferior
  9. ***************************************************************************/
  10. /***************************************************************************
  11. * *
  12. * This program is free software; you can redistribute it and/or modify *
  13. * it under the terms of the GNU General Public License as published by *
  14. * the Free Software Foundation; either version 2 of the License, or *
  15. * (at your option) any later version. *
  16. * *
  17. ***************************************************************************/
  18. #define __STDC_LIMIT_MACROS
  19. #include "config.h"
  20. #ifdef USE_FFMPEG
  21. #include "ADM_default.h"
  22. #include "ADM_threads.h"
  23. extern "C" {
  24. #include "ADM_lavcodec.h"
  25. }
  26. #include "avi_vars.h"
  27. #include "DIA_coreToolkit.h"
  28. #include "ADM_encoder/ADM_vidEncode.hxx"
  29. #include "ADM_encoder/adm_encoder.h"
  30. #include "../oplug_mpegFF/oplug_vcdff.h"
  31. #include "ADM_userInterfaces/ADM_commonUI/DIA_encoding.h"
  32. #include "ADM_audiofilter/audioprocess.hxx"
  33. #include "ADM_audiofilter/audioeng_buildfilters.h"
  34. #include "../ADM_lavformat.h"
  35. #include "ADM_encoder/adm_encConfig.h"
  36. #include "ADM_libraries/ADM_mplex/ADM_mthread.h"
  37. static uint8_t *_buffer = NULL, *_outbuffer = NULL;
  38. static void end(void);
  39. extern const char *getStrFromAudioCodec(uint32_t codec);
  40. extern SelectCodecType videoCodecGetType(void);
  41. static char *twoPass = NULL;
  42. static char *twoFake = NULL;
  43. ps_muxer psMuxerConfig = {PS_MUXER_DVD, 0};
  44. uint8_t oplug_mpegff(const char *name, ADM_OUT_FORMAT type)
  45. {
  46. AVDMGenericVideoStream *_incoming;
  47. Encoder *encoder=NULL;
  48. ADMMpegMuxer *muxer=NULL;
  49. FILE *file=NULL;
  50. uint8_t audioBuffer[48000];
  51. uint32_t audioLen=0;
  52. uint32_t _w,_h,_fps1000,_page,total;
  53. AVDMGenericAudioStream *audio=NULL;
  54. uint32_t len,flags;
  55. uint32_t size;
  56. ADM_MUXER_TYPE mux;
  57. uint32_t audio_encoding=0;
  58. uint32_t real_framenum=0;
  59. uint8_t ret=0;
  60. uint32_t sample_target=0;
  61. uint32_t total_sample=0;
  62. ADMBitstream bitstream(0);
  63. uint32_t audioSum=0;
  64. DIA_encoding *encoding = NULL;
  65. int reuse = 0;
  66. int r = 0;
  67. int frameDelay = 0;
  68. twoPass=new char[strlen(name)+6];
  69. twoFake=new char[strlen(name)+6];
  70. strcpy(twoPass,name);
  71. strcat(twoPass,".stat");
  72. strcpy(twoFake,name);
  73. strcat(twoFake,".fake");
  74. _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
  75. _w=_incoming->getInfo()->width;
  76. _h=_incoming->getInfo()->height;
  77. _fps1000=_incoming->getInfo()->fps1000;
  78. _page=_w*_h;
  79. _page+=_page>>1;
  80. total=_incoming->getInfo()->nb_frames;
  81. if(!total) return 0;
  82. switch(type)
  83. {
  84. default:
  85. ADM_assert(0);
  86. case ADM_ES:
  87. // Else open file (if possible)
  88. mux=MUXER_NONE;
  89. break;
  90. case ADM_TS:
  91. if(!currentaudiostream)
  92. {
  93. GUI_Error_HIG(QT_TR_NOOP("There is no audio track"), NULL);
  94. goto finishvcdff;
  95. }
  96. audio=mpt_getAudioStream();
  97. mux=MUXER_TS;
  98. break;
  99. case ADM_PS:
  100. {
  101. if(!currentaudiostream)
  102. {
  103. GUI_Error_HIG(QT_TR_NOOP("There is no audio track"), NULL);
  104. goto finishvcdff;
  105. }
  106. audio=mpt_getAudioStream();
  107. // Have to check the type
  108. // If it is mpeg2 we use DVD-PS
  109. // If it is mpeg1 we use VCD-PS
  110. // Later check if it is SVCD
  111. if(!audio)
  112. {
  113. GUI_Error_HIG(QT_TR_NOOP("Audio track is not suitable"), NULL);
  114. goto finishvcdff;
  115. }
  116. // Check
  117. WAVHeader *hdr=audio->getInfo();
  118. audio_encoding=hdr->encoding;
  119. switch (psMuxerConfig.muxingType)
  120. {
  121. case PS_MUXER_VCD:
  122. {
  123. if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 44100 || hdr->encoding != WAV_MP2))
  124. {
  125. GUI_Error_HIG(("Incompatible audio"),QT_TR_NOOP( "For VCD, audio must be 44.1 kHz MP2."));
  126. goto finishvcdff;
  127. }
  128. mux = MUXER_VCD;
  129. printf("X*CD: Using VCD PS\n");
  130. break;
  131. }
  132. case PS_MUXER_SVCD:
  133. {
  134. if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 44100 && hdr->encoding == WAV_MP2))
  135. {
  136. GUI_Error_HIG(("Incompatible audio"),QT_TR_NOOP( "For SVCD, audio must be 44.1 kHz MP2."));
  137. goto finishvcdff;
  138. }
  139. mux = MUXER_SVCD;
  140. printf("X*VCD: Using SVCD PS\n");
  141. break;
  142. }
  143. case PS_MUXER_DVD:
  144. {
  145. if (!psMuxerConfig.acceptNonCompliant && (hdr->frequency != 48000 || (hdr->encoding != WAV_MP2 && hdr->encoding != WAV_AC3 && hdr->encoding != WAV_LPCM)))
  146. {
  147. GUI_Error_HIG(("Incompatible audio"), QT_TR_NOOP("For DVD, audio must be 48 kHz MP2, AC3 or LPCM."));
  148. goto finishvcdff;
  149. }
  150. mux = MUXER_DVD;
  151. printf("X*VCD: Using DVD PS\n");
  152. break;
  153. }
  154. }
  155. }
  156. }
  157. // Create muxer
  158. encoder = getVideoEncoder(0);
  159. if (encoder == NULL)
  160. return 0;
  161. encoder->setLogFile(twoPass,total);
  162. if (encoder->isDualPass())
  163. {
  164. printf("Verifying log file\n");
  165. if (encoder->verifyLog(twoPass, total) && GUI_Question(QT_TR_NOOP("Reuse the existing log file?")))
  166. reuse = 1;
  167. }
  168. if(!encoder->configure(_incoming, reuse))
  169. goto finishvcdff;
  170. _buffer=new uint8_t[_page]; // Might overflow if _page only
  171. _outbuffer=new uint8_t[_page];
  172. ADM_assert( _buffer);
  173. ADM_assert( _outbuffer);
  174. encoding =new DIA_encoding(_fps1000);
  175. switch (videoCodecGetType())
  176. {
  177. case CodecRequant:
  178. encoding->setCodec(QT_TR_NOOP("MPEG Requantizer"));
  179. break;
  180. case CodecExternal:
  181. encoding->setCodec(encoder->getDisplayName());
  182. break;
  183. default:
  184. ADM_assert(0);
  185. }
  186. switch(mux)
  187. {
  188. case MUXER_NONE:encoding->setContainer(QT_TR_NOOP("MPEG ES"));break;
  189. case MUXER_TS: encoding->setContainer(QT_TR_NOOP("MPEG TS"));break;
  190. case MUXER_VCD: encoding->setContainer(QT_TR_NOOP("MPEG VCD"));break;
  191. case MUXER_SVCD:encoding->setContainer(QT_TR_NOOP("MPEG SVCD"));break;
  192. case MUXER_DVD: encoding->setContainer(QT_TR_NOOP("MPEG DVD"));break;
  193. default:
  194. ADM_assert(0);
  195. }
  196. // pass 1
  197. if(encoder->isDualPass()) //Cannot be requant
  198. {
  199. if (!reuse)
  200. {
  201. encoding->setPhasis(QT_TR_NOOP("Pass 1/2"));
  202. encoder->startPass1();
  203. bitstream.data = _buffer;
  204. bitstream.bufferSize = _page;
  205. for(uint32_t frame = 0; frame < total; frame++)
  206. {
  207. if (!encoding->isAlive())
  208. {
  209. r = 0;
  210. break;
  211. }
  212. for (;;)
  213. {
  214. bitstream.cleanup(frame);
  215. if (frame + frameDelay >= total)
  216. {
  217. if (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  218. r = encoder->encode(UINT32_MAX, &bitstream);
  219. else
  220. r = 0;
  221. }
  222. else
  223. r = encoder->encode(frame + frameDelay, &bitstream);
  224. if (!r)
  225. {
  226. printf("Encoding of frame %lu failed!\n", frame);
  227. GUI_Error_HIG(QT_TR_NOOP("Error while encoding"), NULL);
  228. break;
  229. }
  230. if (bitstream.len == 0 && (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  231. {
  232. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  233. frameDelay++;
  234. }
  235. else
  236. break;
  237. }
  238. if (!r)
  239. goto finishvcdff;
  240. encoding->setFrame(frame, bitstream.len, bitstream. out_quantizer, total);
  241. }
  242. }
  243. encoder->startPass2();
  244. encoding->reset();
  245. }
  246. switch(type)
  247. {
  248. case ADM_PS:
  249. muxer=new mplexMuxer;
  250. break;
  251. case ADM_TS:
  252. muxer=new tsMuxer;
  253. break;
  254. case ADM_ES:
  255. break;
  256. default:
  257. ADM_assert(0);
  258. }
  259. if(muxer)
  260. {
  261. if(!muxer->open(name,0,mux,avifileinfo,audio->getInfo()))
  262. {
  263. printf("Muxer init failed\n");
  264. goto finishvcdff;
  265. }
  266. double sample_time;
  267. sample_time=total;
  268. sample_time*=1000;
  269. sample_time/=_fps1000; // target_time in second
  270. sample_time*=audio->getInfo()->frequency;
  271. sample_target=(uint32_t)floor(sample_time);
  272. }
  273. else
  274. {
  275. file=fopen(name,"wb");
  276. if(!file)
  277. {
  278. GUI_Error_HIG(QT_TR_NOOP("File error"), QT_TR_NOOP("Cannot open \"%s\" for writing."), name);
  279. goto finishvcdff;
  280. }
  281. }
  282. if(encoder->isDualPass())
  283. encoding->setPhasis (QT_TR_NOOP("Pass 2/2"));
  284. else
  285. encoding->setPhasis (QT_TR_NOOP("Encoding"));
  286. // Set info for audio if any
  287. if(muxer)
  288. {
  289. if(!audioProcessMode())
  290. encoding->setAudioCodec(QT_TR_NOOP("Copy"));
  291. else
  292. encoding->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
  293. }
  294. //**********************************************************
  295. // In that case we do multithreadedwriting (yes!)
  296. //**********************************************************
  297. if(mux==MUXER_DVD || mux==MUXER_SVCD || mux==MUXER_VCD)
  298. {
  299. pthread_t audioThread,videoThread,muxerThread;
  300. muxerMT context;
  301. //
  302. bitstream.data=_outbuffer;
  303. bitstream.bufferSize=_page;
  304. //
  305. memset(&context,0,sizeof(context));
  306. context.videoEncoder=encoder;
  307. context.audioEncoder=audio;
  308. context.muxer=(mplexMuxer *)muxer;
  309. context.nbVideoFrame=total;
  310. context.audioTargetSample=sample_target;
  311. context.audioBuffer=audioBuffer;
  312. context.bitstream=&bitstream;
  313. context.opaque=(void *)encoding;
  314. // start audio thread
  315. ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioSlave,&context));
  316. ADM_assert(!pthread_create(&videoThread,NULL,(THRINP)defaultVideoSlave,&context));
  317. while(1)
  318. {
  319. accessMutex.lock();
  320. if(!encoding->isAlive())
  321. {
  322. context.audioAbort=1;
  323. context.videoAbort=1;
  324. printf("[mpegFF]Waiting for slaves\n");
  325. accessMutex.unlock();
  326. while(1)
  327. {
  328. accessMutex.lock();
  329. if(context.audioDone && context.videoDone)
  330. {
  331. printf("[mpegFF]Both audio & video done\n");
  332. if(context.audioDone==1 && context.videoDone==1) ret=1;
  333. accessMutex.unlock();
  334. goto finishvcdff;
  335. }
  336. accessMutex.unlock();
  337. ADM_usleep(50000);
  338. }
  339. }
  340. if(context.audioDone==2 || context.videoDone==2 ) //ERROR
  341. {
  342. context.audioAbort=1;
  343. context.videoAbort=1;
  344. }
  345. if(context.audioDone && context.videoDone)
  346. {
  347. printf("[mpegFF]Both audio & video done\n");
  348. if(context.audioDone==1 && context.videoDone==1) ret=1;
  349. accessMutex.unlock();
  350. goto finishvcdff;
  351. }
  352. accessMutex.unlock();
  353. ADM_usleep(1000*1000);
  354. }
  355. }
  356. //**********************************************************
  357. // NOT MULTITHREADED
  358. //**********************************************************
  359. bitstream.data=_outbuffer;
  360. bitstream.bufferSize=_page;
  361. r = frameDelay = 0;
  362. for(uint32_t frame = 0; frame < total; frame++)
  363. {
  364. if (!encoding->isAlive())
  365. {
  366. r = 0;
  367. break;
  368. }
  369. for (;;)
  370. {
  371. bitstream.cleanup(frame);
  372. if (frame + frameDelay >= total)
  373. {
  374. if (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  375. r = encoder->encode(UINT32_MAX, &bitstream);
  376. else
  377. r = 0;
  378. }
  379. else
  380. r = encoder->encode(frame + frameDelay, &bitstream);
  381. if (!r)
  382. {
  383. printf("Encoding of frame %lu failed!\n", frame);
  384. GUI_Error_HIG(QT_TR_NOOP("Error while encoding"), NULL);
  385. break;
  386. }
  387. if (bitstream.len == 0 && (encoder->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  388. {
  389. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  390. frameDelay++;
  391. }
  392. else
  393. break;
  394. }
  395. if (!r)
  396. goto finishvcdff;
  397. if(file)
  398. {
  399. fwrite(_outbuffer,bitstream.len,1,file);
  400. }
  401. else
  402. {
  403. muxer->writeVideoPacket(&bitstream);
  404. real_framenum++;
  405. if(total_sample < sample_target)
  406. {
  407. uint32_t samples;
  408. while(muxer->needAudio() && total_sample < sample_target)
  409. {
  410. if (!audio->getPacket(audioBuffer, &audioLen, &samples))
  411. break;
  412. if(audioLen)
  413. {
  414. muxer->writeAudioPacket(audioLen, audioBuffer);
  415. total_sample += samples;
  416. audioSum += audioLen;
  417. }
  418. }
  419. }
  420. }
  421. encoding->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
  422. encoding->setAudioSize(audioSum);
  423. }
  424. ret=1;
  425. finishvcdff:
  426. printf("[MPEGFF] Finishing..\n");
  427. if (encoding)
  428. delete encoding;
  429. end();
  430. if(file)
  431. {
  432. fclose(file);
  433. file=NULL;
  434. }
  435. else if(muxer)
  436. {
  437. muxer->close();
  438. delete muxer;
  439. muxer=NULL;
  440. }
  441. delete encoder;
  442. if (audio)
  443. deleteAudioFilter(audio);
  444. return ret;
  445. }
  446. void end (void)
  447. {
  448. delete [] _buffer;
  449. delete [] _outbuffer;
  450. _buffer =NULL;
  451. _outbuffer=NULL;
  452. if(twoPass) delete [] twoPass;
  453. if(twoFake) delete [] twoFake;
  454. twoPass=twoFake=NULL;
  455. }
  456. AVDMGenericAudioStream *mpt_getAudioStream (void)
  457. {
  458. AVDMGenericAudioStream *audio = NULL;
  459. if (audioProcessMode ()) // else Raw copy mode
  460. {
  461. if (currentaudiostream->isCompressed ())
  462. {
  463. if (!currentaudiostream->isDecompressable ())
  464. {
  465. return NULL;
  466. }
  467. }
  468. audio = buildAudioFilter (currentaudiostream, video_body->getTime (frameStart));
  469. }
  470. else // copymode
  471. {
  472. // else prepare the incoming raw stream
  473. // audio copy mode here
  474. audio = buildAudioFilter (currentaudiostream,video_body->getTime (frameStart));
  475. }
  476. return audio;
  477. }
  478. #endif
  479. // EOF