PageRenderTime 71ms CodeModel.GetById 41ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/Codec/Avidemux-EditorPlugin/avidemux-2.4.4/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp

https://bitbucket.org/gianni/vaet
C++ | 545 lines | 430 code | 73 blank | 42 comment | 75 complexity | b66caca48af2e971886bc04c0e21ea53 MD5 | raw file
Possible License(s): 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. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <math.h>
  24. #include <pthread.h>
  25. #define WIN32_CLASH
  26. #ifdef USE_FFMPEG
  27. extern "C" {
  28. #include "ADM_lavcodec.h"
  29. };
  30. #include "avi_vars.h"
  31. #include "prototype.h"
  32. #include "ADM_colorspace/colorspace.h"
  33. #include "ADM_toolkit/toolkit.hxx"
  34. #include <ADM_assert.h>
  35. #include "ADM_video/ADM_genvideo.hxx"
  36. #include "ADM_filter/video_filters.h"
  37. #include "ADM_encoder/ADM_vidEncode.hxx"
  38. #include "ADM_encoder/adm_encoder.h"
  39. //#include "ADM_codecs/ADM_divxEncode.h"
  40. //#include "ADM_encoder/adm_encdivx.h"
  41. #include "ADM_codecs/ADM_ffmpeg.h"
  42. #include "ADM_encoder/adm_encffmpeg.h"
  43. #include "oplug_mpegFF/oplug_vcdff.h"
  44. #include "DIA_encoding.h"
  45. #include "ADM_audiofilter/audioprocess.hxx"
  46. #include "ADM_audiofilter/audioeng_buildfilters.h"
  47. #include "ADM_lavformat/ADM_lavformat.h"
  48. #include "ADM_encoder/adm_encConfig.h"
  49. #include "ADM_encoder/ADM_vidEncode.hxx"
  50. #include "ADM_mplex/ADM_mthread.h"
  51. #include "ADM_toolkit/ADM_audioQueue.h"
  52. #include "ADM_osSupport/ADM_debugID.h"
  53. #define MODULE_NAME MODULE_MP4
  54. #include "ADM_osSupport/ADM_debug.h"
  55. static uint8_t *_buffer=NULL,*_outbuffer=NULL;
  56. static void end (void);
  57. extern const char *getStrFromAudioCodec( uint32_t codec);
  58. extern SelectCodecType current_codec;
  59. static char *twoPass=NULL;
  60. static char *twoFake=NULL;
  61. extern AVDMGenericAudioStream *mpt_getAudioStream(void);
  62. uint8_t prepareDualPass(uint32_t bufferSize,uint8_t *buffer,char *TwoPassLogFile,DIA_encoding *encoding_gui,Encoder *_encode,uint32_t total);
  63. uint8_t extractVolHeader(uint8_t *data,uint32_t dataSize,uint32_t *headerSize);
  64. extern void UI_purge(void );
  65. /*
  66. */
  67. uint8_t oplug_mp4(const char *name, ADM_OUT_FORMAT type)
  68. {
  69. AVDMGenericVideoStream *_incoming=NULL;
  70. AVDMGenericAudioStream *audio=NULL;
  71. uint8_t audioBuffer[48000];
  72. uint8_t *videoBuffer=NULL;
  73. uint32_t alen;//,flags;
  74. uint32_t size;
  75. uint32_t sample_got=0,sample;
  76. uint32_t extraDataSize=0;
  77. uint8_t *extraData=NULL;
  78. lavMuxer *muxer=NULL;
  79. aviInfo info;
  80. uint32_t width,height;
  81. DIA_encoding *encoding_gui=NULL;
  82. Encoder *_encode=NULL;
  83. char *TwoPassLogFile=NULL;
  84. uint32_t total=0;
  85. uint32_t videoExtraDataSize=0;
  86. uint8_t *videoExtraData=NULL;
  87. uint8_t *dummy,err;
  88. WAVHeader *audioinfo=NULL;
  89. ADMBitstream bitstream(0);
  90. ADM_MUXER_TYPE muxerType=MUXER_MP4;
  91. uint8_t dualPass=0;
  92. uint8_t r=0;
  93. pthread_t audioThread;
  94. audioQueueMT context;
  95. PacketQueue *pq = NULL;//("MP4 audioQ",50,2*1024*1024);
  96. uint32_t totalAudioSize=0;
  97. uint32_t sent=0;
  98. const char *containerTitle;
  99. int frameDelay = 0;
  100. bool receivedFrame = false;
  101. switch(type)
  102. {
  103. case ADM_PSP:muxerType=MUXER_PSP;containerTitle=QT_TR_NOOP("PSP");break;
  104. case ADM_MP4:muxerType=MUXER_MP4;containerTitle=QT_TR_NOOP("MP4");break;
  105. case ADM_MATROSKA:muxerType=MUXER_MATROSKA;containerTitle=QT_TR_NOOP("MKV");break;
  106. default:
  107. ADM_assert(0);
  108. }
  109. // Setup video
  110. if(videoProcessMode())
  111. {
  112. _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
  113. }else
  114. {
  115. _incoming = getFirstVideoFilter (frameStart,frameEnd-frameStart);
  116. }
  117. videoBuffer=new uint8_t[_incoming->getInfo()->width*_incoming->getInfo()->height*3];
  118. // Set global header encoding, needed for H264
  119. _encode = getVideoEncoder (_incoming->getInfo()->width,
  120. _incoming->getInfo()->height,1);
  121. total= _incoming->getInfo()->nb_frames;
  122. encoding_gui=new DIA_encoding(_incoming->getInfo()->fps1000);
  123. bitstream.bufferSize=_incoming->getInfo()->width*_incoming->getInfo()->height*3;
  124. if (!_encode)
  125. {
  126. GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the video stream"), NULL);
  127. goto stopit;
  128. }
  129. // init compressor
  130. encoding_gui->setContainer(containerTitle);
  131. encoding_gui->setAudioCodec(QT_TR_NOOP("None"));
  132. if(!videoProcessMode())
  133. encoding_gui->setCodec(QT_TR_NOOP("Copy"));
  134. else
  135. encoding_gui->setCodec(_encode->getDisplayName());
  136. TwoPassLogFile=new char[strlen(name)+6];
  137. strcpy(TwoPassLogFile,name);
  138. strcat(TwoPassLogFile,".stat");
  139. _encode->setLogFile(TwoPassLogFile,total);
  140. if (!_encode->configure (_incoming))
  141. {
  142. GUI_Error_HIG (QT_TR_NOOP("Filter init failed"), NULL);
  143. goto stopit;
  144. };
  145. dualPass=_encode->isDualPass();
  146. if(dualPass)
  147. {
  148. if(!prepareDualPass(bitstream.bufferSize,videoBuffer,TwoPassLogFile,encoding_gui,_encode,total))
  149. goto stopit;
  150. }else
  151. {
  152. encoding_gui->setPhasis (QT_TR_NOOP("Encoding"));
  153. }
  154. info.width=_incoming->getInfo()->width;
  155. info.height=_incoming->getInfo()->height;
  156. info.nb_frames=_incoming->getInfo()->nb_frames;
  157. info.fps1000=_incoming->getInfo()->fps1000;
  158. info.fcc=*(uint32_t *)_encode->getCodecName(); //FIXME
  159. _encode->hasExtraHeaderData( &videoExtraDataSize,&dummy);
  160. if(videoExtraDataSize)
  161. {
  162. printf("We have extradata for video in copy mode (%d)\n",videoExtraDataSize);
  163. videoExtraData=new uint8_t[videoExtraDataSize];
  164. memcpy(videoExtraData,dummy,videoExtraDataSize);
  165. }
  166. ADM_assert(_encode);
  167. bitstream.data = videoBuffer;
  168. // ____________Setup audio__________________
  169. if(currentaudiostream)
  170. {
  171. audio=mpt_getAudioStream();
  172. if(!audio)
  173. {
  174. GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the audio stream"), NULL);
  175. goto stopit;
  176. }
  177. }
  178. if(audio)
  179. {
  180. audioinfo=audio->getInfo();
  181. if (muxerType == MUXER_MP4)
  182. {
  183. switch (audioinfo->encoding)
  184. {
  185. case WAV_MP2:
  186. case WAV_MP3:
  187. case WAV_AAC:
  188. case WAV_AAC_HE:
  189. break;
  190. default:
  191. if (!GUI_YesNo(QT_TR_NOOP("Invalid audio stream detected"), QT_TR_NOOP("The audio stream may be invalid for this container.\n\nContinue anyway?")))
  192. goto stopit;
  193. }
  194. }
  195. audio->extraData(&extraDataSize,&extraData);
  196. if(audioProcessMode())
  197. encoding_gui->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding));
  198. else
  199. encoding_gui->setAudioCodec(QT_TR_NOOP("Copy"));
  200. }else
  201. {
  202. encoding_gui->setAudioCodec(QT_TR_NOOP("None"));
  203. }
  204. //_____________ Loop _____________________
  205. encoding_gui->setContainer(containerTitle);
  206. if(!videoProcessMode())
  207. encoding_gui->setCodec(QT_TR_NOOP("Copy"));
  208. else
  209. encoding_gui->setCodec(_encode->getDisplayName());
  210. //
  211. UI_purge();
  212. //_____________ Start Audio thread _____________________
  213. if(audio)
  214. {
  215. pq=new PacketQueue("MP4 audioQ",5000,2*1024*1024);
  216. memset(&context,0,sizeof(context));
  217. context.audioEncoder=audio;
  218. context.audioTargetSample=0xFFFF0000; ; //FIXME
  219. context.packetQueue=pq;
  220. // start audio thread
  221. ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioQueueSlave,&context));
  222. ADM_usleep(4000);
  223. }
  224. //_____________GO !___________________
  225. for (uint32_t frame = 0; frame < total; frame++)
  226. {
  227. if (!encoding_gui->isAlive())
  228. {
  229. r = 0;
  230. break;
  231. }
  232. for (;;)
  233. {
  234. bitstream.cleanup(frame);
  235. #ifdef USE_X264
  236. if (current_codec == CodecX264)
  237. bitstream.dtsFrame = UINT32_MAX; // let libavformat calculate it
  238. #endif
  239. if (frame + frameDelay >= total)
  240. {
  241. if (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  242. r = _encode->encode(UINT32_MAX, &bitstream);
  243. else
  244. r = 0;
  245. }
  246. else
  247. r = _encode->encode(frame + frameDelay, &bitstream);
  248. if (!r)
  249. {
  250. printf("Encoding of frame %lu failed!\n", frame);
  251. GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
  252. break;
  253. }
  254. else if (!receivedFrame && bitstream.len > 0)
  255. {
  256. if (!(bitstream.flags & AVI_KEY_FRAME))
  257. {
  258. GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"), QT_TR_NOOP("The beginning frame is not a key frame.\nPlease move the A marker."));
  259. r = 0;
  260. break;
  261. }
  262. else
  263. receivedFrame = true;
  264. }
  265. if (bitstream.len == 0 && (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  266. {
  267. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  268. frameDelay++;
  269. }
  270. else
  271. break;
  272. }
  273. if (!r)
  274. break;
  275. if (!muxer)
  276. {
  277. // If needed get VOL header
  278. if (isMpeg4Compatible(info.fcc) && !videoExtraDataSize && bitstream.len)
  279. {
  280. // And put them as extradata for esds atom
  281. uint32_t voslen = 0;
  282. if(extractVolHeader(videoBuffer, bitstream.len, &voslen))
  283. {
  284. if (voslen)
  285. {
  286. videoExtraDataSize = voslen;
  287. videoExtraData = new uint8_t[videoExtraDataSize];
  288. memcpy(videoExtraData, videoBuffer, videoExtraDataSize);
  289. }
  290. }
  291. else
  292. printf("Oops should be settings data for esds\n");
  293. }
  294. muxer = new lavMuxer;
  295. if (!muxer->open(
  296. name,
  297. 2000000, // Muxrate
  298. muxerType,
  299. &info, videoExtraDataSize, videoExtraData,
  300. audioinfo, extraDataSize, extraData))
  301. break;
  302. }
  303. while (muxer->needAudio())
  304. {
  305. if (pq->Pop(audioBuffer, &alen, &sample))
  306. {
  307. if (alen)
  308. {
  309. muxer->writeAudioPacket(alen, audioBuffer, sample_got);
  310. totalAudioSize += alen;
  311. encoding_gui->setAudioSize(totalAudioSize);
  312. sample_got += sample;
  313. }
  314. }
  315. else
  316. break;
  317. }
  318. muxer->writeVideoPacket(&bitstream);
  319. encoding_gui->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
  320. }
  321. stopit:
  322. printf("2nd pass, sent %u frames\n", bitstream.frameNumber + frameDelay);
  323. // Flush slave Q
  324. if(pq)
  325. {
  326. context.audioAbort=1;
  327. pq->Abort();
  328. // Wait for audio slave to be over
  329. while(!context.audioDone)
  330. {
  331. printf("Waiting Audio thread\n");
  332. ADM_usleep(500000);
  333. }
  334. delete pq;
  335. }
  336. //
  337. if(muxer) muxer->close();
  338. if(encoding_gui) delete encoding_gui;
  339. if(TwoPassLogFile) delete [] TwoPassLogFile;
  340. if(videoBuffer) delete [] videoBuffer;
  341. if(muxer) delete muxer;
  342. if(_encode) delete _encode;
  343. if(videoExtraData) delete [] videoExtraData;
  344. // Cleanup
  345. deleteAudioFilter (audio);
  346. return r;
  347. }
  348. uint8_t prepareDualPass(uint32_t bufferSize,uint8_t *buffer,char *TwoPassLogFile,DIA_encoding *encoding_gui,Encoder *_encode,uint32_t total)
  349. {
  350. uint32_t len, flag;
  351. FILE *tmp;
  352. uint8_t reuse=0,r;
  353. ADMBitstream bitstream(0);
  354. int frameDelay = 0;
  355. bool receivedFrame = false;
  356. aprintf("\n** Dual pass encoding**\n");
  357. if((tmp=fopen(TwoPassLogFile,"rt")))
  358. {
  359. fclose(tmp);
  360. if(GUI_Question(QT_TR_NOOP("\n Reuse the existing log-file ?")))
  361. {
  362. reuse=1;
  363. }
  364. }
  365. if(!reuse)
  366. {
  367. encoding_gui->setPhasis (QT_TR_NOOP("1st Pass"));
  368. aprintf("**Pass 1:%lu\n",total);
  369. _encode->startPass1 ();
  370. bitstream.data=buffer;
  371. bitstream.bufferSize=bufferSize;
  372. for (uint32_t frame = 0; frame < total; frame++)
  373. {
  374. if (!encoding_gui->isAlive())
  375. {
  376. r = 0;
  377. break;
  378. }
  379. for (;;)
  380. {
  381. bitstream.cleanup(frame);
  382. #ifdef USE_X264
  383. if (current_codec == CodecX264)
  384. bitstream.dtsFrame = UINT32_MAX; // let libavformat calculate it
  385. #endif
  386. if (frame + frameDelay >= total)
  387. {
  388. if (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  389. r = _encode->encode(UINT32_MAX, &bitstream);
  390. else
  391. r = 0;
  392. }
  393. else
  394. r = _encode->encode(frame + frameDelay, &bitstream);
  395. if (!r)
  396. {
  397. printf("Encoding of frame %lu failed!\n", frame);
  398. GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
  399. break;
  400. }
  401. else if (!receivedFrame && bitstream.len > 0)
  402. {
  403. if (!(bitstream.flags & AVI_KEY_FRAME))
  404. {
  405. GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"), QT_TR_NOOP("The beginning frame is not a key frame.\nPlease move the A marker."));
  406. r = 0;
  407. break;
  408. }
  409. else
  410. receivedFrame = true;
  411. }
  412. if (bitstream.len == 0 && (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  413. {
  414. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  415. frameDelay++;
  416. }
  417. else
  418. break;
  419. }
  420. if (!r)
  421. return 0;
  422. encoding_gui->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
  423. }
  424. encoding_gui->reset();
  425. }// End of reuse
  426. if(!_encode->startPass2 ())
  427. {
  428. printf("Pass2 ignition failed\n");
  429. return 0;
  430. }
  431. printf("First pass : send %u frames\n", bitstream.frameNumber + frameDelay);
  432. encoding_gui->setPhasis (QT_TR_NOOP("2nd Pass"));
  433. return 1;
  434. }
  435. void end (void)
  436. {
  437. }
  438. uint8_t extractVolHeader(uint8_t *data,uint32_t dataSize,uint32_t *headerSize)
  439. {
  440. // Search startcode
  441. uint8_t b;
  442. uint32_t idx=0;
  443. uint32_t mw,mh;
  444. uint32_t time_inc;
  445. *headerSize=0;
  446. while(dataSize)
  447. {
  448. uint32_t startcode=0xffffffff;
  449. while(dataSize>2)
  450. {
  451. startcode=(startcode<<8)+data[idx];
  452. idx++;
  453. dataSize--;
  454. if((startcode&0xffffff)==1) break;
  455. }
  456. printf("Startcodec:%x\n",data[idx]);
  457. if(data[idx]==0xB6 && idx>4) // vop start
  458. {
  459. printf("Vop start found at %d\n",idx);
  460. *headerSize=idx-4;
  461. return 1;
  462. }
  463. }
  464. printf("No vop start found\n");
  465. return 0;
  466. }
  467. #endif
  468. // EOF