PageRenderTime 27ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/Avidemux/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp

http://mulder.googlecode.com/
C++ | 530 lines | 418 code | 71 blank | 41 comment | 80 complexity | 2e066547e5d208c65e475b5ec7229c99 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. #include "ADM_default.h"
  21. #include "ADM_threads.h"
  22. #ifdef USE_FFMPEG
  23. extern "C" {
  24. #include "ADM_lavcodec.h"
  25. };
  26. #include "avi_vars.h"
  27. #include "prototype.h"
  28. //#include "ADM_colorspace/colorspace.h"
  29. #include "DIA_coreToolkit.h"
  30. #include "ADM_videoFilter.h"
  31. #include "ADM_videoFilter_internal.h"
  32. #include "ADM_encoder/ADM_vidEncode.hxx"
  33. #include "ADM_encoder/adm_encoder.h"
  34. #include "../oplug_mpegFF/oplug_vcdff.h"
  35. #include "ADM_userInterfaces/ADM_commonUI/DIA_encoding.h"
  36. #include "ADM_audiofilter/audioprocess.hxx"
  37. #include "ADM_audiofilter/audioeng_buildfilters.h"
  38. #include "../ADM_lavformat.h"
  39. #include "ADM_encoder/adm_encConfig.h"
  40. #include "ADM_encoder/ADM_vidEncode.hxx"
  41. #include "ADM_libraries/ADM_mplex/ADM_mthread.h"
  42. #include "ADM_toolkit/ADM_audioQueue.h"
  43. #include "ADM_osSupport/ADM_debugID.h"
  44. #define MODULE_NAME MODULE_MP4
  45. #include "ADM_osSupport/ADM_debug.h"
  46. static uint8_t *_buffer=NULL,*_outbuffer=NULL;
  47. static void end (void);
  48. extern const char *getStrFromAudioCodec( uint32_t codec);
  49. static char *twoPass=NULL;
  50. static char *twoFake=NULL;
  51. extern AVDMGenericAudioStream *mpt_getAudioStream(void);
  52. uint8_t prepareDualPass(uint32_t bufferSize,uint8_t *buffer,DIA_encoding *encoding_gui,Encoder *_encode,uint32_t total,int reuse);
  53. uint8_t extractVolHeader(uint8_t *data,uint32_t dataSize,uint32_t *headerSize);
  54. extern void UI_purge(void );
  55. /*
  56. */
  57. uint8_t oplug_mp4(const char *name, ADM_OUT_FORMAT type)
  58. {
  59. AVDMGenericVideoStream *_incoming=NULL;
  60. AVDMGenericAudioStream *audio=NULL;
  61. uint8_t audioBuffer[48000];
  62. uint8_t *videoBuffer=NULL;
  63. uint32_t alen;//,flags;
  64. uint32_t size;
  65. uint32_t sample_got=0,sample;
  66. uint32_t extraDataSize=0;
  67. uint8_t *extraData=NULL;
  68. lavMuxer *muxer=NULL;
  69. aviInfo info;
  70. uint32_t width,height;
  71. DIA_encoding *encoding_gui=NULL;
  72. Encoder *_encode=NULL;
  73. char *TwoPassLogFile=NULL;
  74. uint32_t total=0;
  75. uint32_t videoExtraDataSize=0;
  76. uint8_t *videoExtraData=NULL;
  77. uint8_t *dummy,err;
  78. WAVHeader *audioinfo=NULL;
  79. ADMBitstream bitstream(0);
  80. ADM_MUXER_TYPE muxerType=MUXER_MP4;
  81. uint8_t dualPass=0;
  82. uint8_t r=0;
  83. pthread_t audioThread;
  84. audioQueueMT context;
  85. PacketQueue *pq = NULL;//("MP4 audioQ",50,2*1024*1024);
  86. uint32_t totalAudioSize=0;
  87. uint32_t sent=0;
  88. const char *containerTitle;
  89. int reuse = 0;
  90. int frameDelay = 0;
  91. bool receivedFrame = false;
  92. switch(type)
  93. {
  94. case ADM_PSP:muxerType=MUXER_PSP;containerTitle=QT_TR_NOOP("PSP");break;
  95. case ADM_MP4:muxerType=MUXER_MP4;containerTitle=QT_TR_NOOP("MP4");break;
  96. case ADM_MATROSKA:muxerType=MUXER_MATROSKA;containerTitle=QT_TR_NOOP("MKV");break;
  97. default:
  98. ADM_assert(0);
  99. }
  100. // Setup video
  101. if(videoProcessMode())
  102. {
  103. _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart);
  104. }else
  105. {
  106. _incoming = getFirstVideoFilter (frameStart,frameEnd-frameStart);
  107. }
  108. videoBuffer=new uint8_t[_incoming->getInfo()->width*_incoming->getInfo()->height*3];
  109. // Set global header encoding, needed for H264
  110. _encode = getVideoEncoder(1);
  111. total= _incoming->getInfo()->nb_frames;
  112. encoding_gui=new DIA_encoding(_incoming->getInfo()->fps1000);
  113. bitstream.bufferSize=_incoming->getInfo()->width*_incoming->getInfo()->height*3;
  114. if (!_encode)
  115. {
  116. GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the video stream"), NULL);
  117. goto stopit;
  118. }
  119. // init compressor
  120. encoding_gui->setContainer(containerTitle);
  121. encoding_gui->setAudioCodec(QT_TR_NOOP("None"));
  122. if(!videoProcessMode())
  123. encoding_gui->setCodec(QT_TR_NOOP("Copy"));
  124. else
  125. encoding_gui->setCodec(_encode->getDisplayName());
  126. TwoPassLogFile=new char[strlen(name)+6];
  127. strcpy(TwoPassLogFile,name);
  128. strcat(TwoPassLogFile,".stat");
  129. _encode->setLogFile(TwoPassLogFile,total);
  130. dualPass = _encode->isDualPass();
  131. if (dualPass)
  132. {
  133. FILE *tmp;
  134. if ((tmp = fopen(TwoPassLogFile,"rt")))
  135. {
  136. fclose(tmp);
  137. if (GUI_Question(QT_TR_NOOP("Reuse the existing log file?")))
  138. reuse = 1;
  139. }
  140. }
  141. if (!_encode->configure (_incoming, reuse))
  142. {
  143. GUI_Error_HIG (QT_TR_NOOP("Filter init failed"), NULL);
  144. goto stopit;
  145. }
  146. if(dualPass)
  147. {
  148. if(!prepareDualPass(bitstream.bufferSize,videoBuffer,encoding_gui,_encode,total,reuse))
  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. if (videoCodecGetType() == CodecExternal && strcmp(videoCodecPluginGetGuid(), "32BCB447-21C9-4210-AE9A-4FCE6C8588AE") == 0)
  236. bitstream.dtsFrame = UINT32_MAX; // let libavformat calculate it
  237. if (frame + frameDelay >= total)
  238. {
  239. if (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  240. r = _encode->encode(UINT32_MAX, &bitstream);
  241. else
  242. r = 0;
  243. }
  244. else
  245. r = _encode->encode(frame + frameDelay, &bitstream);
  246. if (!r)
  247. {
  248. printf("Encoding of frame %lu failed!\n", frame);
  249. GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
  250. break;
  251. }
  252. else if (!receivedFrame && bitstream.len > 0)
  253. {
  254. if (!(bitstream.flags & AVI_KEY_FRAME))
  255. {
  256. GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"), QT_TR_NOOP("The beginning frame is not a key frame.\nPlease move the A marker."));
  257. r = 0;
  258. break;
  259. }
  260. else
  261. receivedFrame = true;
  262. }
  263. if (bitstream.len == 0 && (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  264. {
  265. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  266. frameDelay++;
  267. }
  268. else
  269. break;
  270. }
  271. if (!r)
  272. break;
  273. if (!muxer)
  274. {
  275. // If needed get VOL header
  276. if (isMpeg4Compatible(info.fcc) && !videoExtraDataSize && bitstream.len)
  277. {
  278. // And put them as extradata for esds atom
  279. uint32_t voslen = 0;
  280. if(extractVolHeader(videoBuffer, bitstream.len, &voslen))
  281. {
  282. if (voslen)
  283. {
  284. videoExtraDataSize = voslen;
  285. videoExtraData = new uint8_t[videoExtraDataSize];
  286. memcpy(videoExtraData, videoBuffer, videoExtraDataSize);
  287. }
  288. }
  289. else
  290. printf("Oops should be settings data for esds\n");
  291. }
  292. muxer = new lavMuxer;
  293. if (!muxer->open(
  294. name,
  295. 2000000, // Muxrate
  296. muxerType,
  297. &info, videoExtraDataSize, videoExtraData,
  298. audioinfo, extraDataSize, extraData))
  299. break;
  300. }
  301. while (muxer->needAudio())
  302. {
  303. if (pq->Pop(audioBuffer, &alen, &sample))
  304. {
  305. if (alen)
  306. {
  307. muxer->writeAudioPacket(alen, audioBuffer, sample_got);
  308. totalAudioSize += alen;
  309. encoding_gui->setAudioSize(totalAudioSize);
  310. sample_got += sample;
  311. }
  312. }
  313. else
  314. break;
  315. }
  316. muxer->writeVideoPacket(&bitstream);
  317. encoding_gui->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
  318. }
  319. stopit:
  320. printf("2nd pass, sent %u frames\n", bitstream.frameNumber + frameDelay);
  321. // Flush slave Q
  322. if(pq)
  323. {
  324. context.audioAbort=1;
  325. pq->Abort();
  326. // Wait for audio slave to be over
  327. while(!context.audioDone)
  328. {
  329. printf("Waiting Audio thread\n");
  330. ADM_usleep(500000);
  331. }
  332. delete pq;
  333. }
  334. //
  335. if(muxer) muxer->close();
  336. if(encoding_gui) delete encoding_gui;
  337. if(TwoPassLogFile) delete [] TwoPassLogFile;
  338. if(videoBuffer) delete [] videoBuffer;
  339. if(muxer) delete muxer;
  340. if(_encode) delete _encode;
  341. if(videoExtraData) delete [] videoExtraData;
  342. // Cleanup
  343. deleteAudioFilter (audio);
  344. return r;
  345. }
  346. uint8_t prepareDualPass(uint32_t bufferSize,uint8_t *buffer,DIA_encoding *encoding_gui,Encoder *_encode,uint32_t total,int reuse)
  347. {
  348. uint32_t len, flag;
  349. uint8_t r;
  350. ADMBitstream bitstream(0);
  351. int frameDelay = 0;
  352. bool receivedFrame = false;
  353. aprintf("\n** Dual pass encoding**\n");
  354. if(!reuse)
  355. {
  356. encoding_gui->setPhasis (QT_TR_NOOP("1st Pass"));
  357. aprintf("**Pass 1:%lu\n",total);
  358. _encode->startPass1 ();
  359. bitstream.data=buffer;
  360. bitstream.bufferSize=bufferSize;
  361. for (uint32_t frame = 0; frame < total; frame++)
  362. {
  363. if (!encoding_gui->isAlive())
  364. {
  365. r = 0;
  366. break;
  367. }
  368. for (;;)
  369. {
  370. bitstream.cleanup(frame);
  371. if (videoCodecGetType() == CodecExternal && strcmp(videoCodecPluginGetGuid(), "32BCB447-21C9-4210-AE9A-4FCE6C8588AE") == 0)
  372. bitstream.dtsFrame = UINT32_MAX; // let libavformat calculate it
  373. if (frame + frameDelay >= total)
  374. {
  375. if (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH)
  376. r = _encode->encode(UINT32_MAX, &bitstream);
  377. else
  378. r = 0;
  379. }
  380. else
  381. r = _encode->encode(frame + frameDelay, &bitstream);
  382. if (!r)
  383. {
  384. printf("Encoding of frame %lu failed!\n", frame);
  385. GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL);
  386. break;
  387. }
  388. else if (!receivedFrame && bitstream.len > 0)
  389. {
  390. if (!(bitstream.flags & AVI_KEY_FRAME))
  391. {
  392. GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"), QT_TR_NOOP("The beginning frame is not a key frame.\nPlease move the A marker."));
  393. r = 0;
  394. break;
  395. }
  396. else
  397. receivedFrame = true;
  398. }
  399. if (bitstream.len == 0 && (_encode->getRequirements() & ADM_ENC_REQ_NULL_FLUSH))
  400. {
  401. printf("skipping frame: %u size: %i\n", frame + frameDelay, bitstream.len);
  402. frameDelay++;
  403. }
  404. else
  405. break;
  406. }
  407. if (!r)
  408. return 0;
  409. encoding_gui->setFrame(frame, bitstream.len, bitstream.out_quantizer, total);
  410. }
  411. encoding_gui->reset();
  412. }// End of reuse
  413. if(!_encode->startPass2 ())
  414. {
  415. printf("Pass2 ignition failed\n");
  416. return 0;
  417. }
  418. printf("First pass : send %u frames\n", bitstream.frameNumber + frameDelay);
  419. encoding_gui->setPhasis (QT_TR_NOOP("2nd Pass"));
  420. return 1;
  421. }
  422. void end (void)
  423. {
  424. }
  425. uint8_t extractVolHeader(uint8_t *data,uint32_t dataSize,uint32_t *headerSize)
  426. {
  427. // Search startcode
  428. uint8_t b;
  429. uint32_t idx=0;
  430. uint32_t mw,mh;
  431. uint32_t time_inc;
  432. *headerSize=0;
  433. while(dataSize)
  434. {
  435. uint32_t startcode=0xffffffff;
  436. while(dataSize>2)
  437. {
  438. startcode=(startcode<<8)+data[idx];
  439. idx++;
  440. dataSize--;
  441. if((startcode&0xffffff)==1) break;
  442. }
  443. printf("Startcodec:%x\n",data[idx]);
  444. if(data[idx]==0xB6 && idx>4) // vop start
  445. {
  446. printf("Vop start found at %d\n",idx);
  447. *headerSize=idx-4;
  448. return 1;
  449. }
  450. }
  451. printf("No vop start found\n");
  452. return 0;
  453. }
  454. #endif
  455. // EOF