1 /**
2 \file ADM_videoCopyFromAnnexB
3 \brief Convert from annexB h264 to iso on the fly
4 (c) Mean 2010/GPLv2
5
6 */
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16 #include "ADM_default.h"
17 #include "ADM_videoCopy.h"
18 #include "ADM_edit.hxx"
19 #include "ADM_coreUtils.h"
20 #include "ADM_h264_tag.h"
21 #include "ADM_videoInfoExtractor.h"
22
23 using std::string;
24 extern "C"
25 {
26 #include "libavcodec/avcodec.h"
27 }
28 #include "ADM_h265_tag.h"
29 extern ADM_Composer *video_body; // Fixme!
30
31 //#warning fixme : double definition
32
33 //#define ANNEX_B_DEBUG
34
35 #if defined(ANNEX_B_DEBUG)
36 #define aprintf ADM_info
37 #define check isNalValid
38 #else
39 #define aprintf(...) {}
40 #define check(...) {}
41 #endif
42
43 #ifdef MAX_NALU_PER_CHUNK
44 #undef MAX_NALU_PER_CHUNK
45 #define MAX_NALU_PER_CHUNK 20
46 #endif
47
readBE32(uint8_t * p)48 static uint32_t readBE32(uint8_t *p)
49 {
50 uint32_t v=(p[0]<<8)+p[1];
51 uint32_t u=(p[2]<<8)+p[3];
52 return (v<<16)+u;
53 }
54
55 static const char *nalType[13]=
56 {
57 "invalid","nonIdr","invalid","invalid","invalid",
58 "idr","sei","sps","pps","au delimiter","invalid","invalid","filler"
59 };
isNalValid(int nal)60 static bool isNalValid(int nal)
61 {
62 nal&=0x1f;
63 switch(nal)
64 {
65 case 1:case 5:case 6: case 7: case 8: case 9:case 0xc:
66 break;
67 default:
68 ADM_warning("Invalid NAL 0x%x\n",nal);break;
69 }
70 if(nal<=12) ADM_info("Nal : %s",nalType[nal]);
71 return true;
72 }
73 /**
74 * \fn extractExtraDataH264Internal
75 */
extractExtraDataH264Internal(void)76 bool ADM_videoStreamCopyFromAnnexB::extractExtraDataH264Internal(void)
77 {
78 NALU_descriptor desc[MAX_NALU_PER_CHUNK];
79 int nbNalu=ADM_splitNalu(myBitstream->data, myBitstream->data+myBitstream->len, MAX_NALU_PER_CHUNK, desc);
80 // search sps
81 uint32_t spsLen=0, ppsLen=0;
82 int indexSps,indexPps;
83
84 indexSps=ADM_findNalu(NAL_SPS,nbNalu,desc);
85 if(-1==indexSps)
86 {
87 ADM_error("Cannot find SPS");
88 return false;
89 }
90 indexPps=ADM_findNalu(NAL_PPS,nbNalu,desc);
91 if(-1==indexPps)
92 {
93 ADM_error("Cannot find SPS");
94 return false;
95 }else
96 {
97 int count=desc[indexPps].size;
98 uint8_t *ptr=desc[indexPps].start+count-1;
99 while(count > 4)
100 {
101 if(*ptr) break;
102 ptr--;
103 count--;
104 }
105 ADM_info("PPS removed zero filler %d -> %d\n",(int)desc[indexPps].size,(int)count);
106 desc[indexPps].size=count;
107 }
108
109 spsLen=desc[indexSps].size;
110 ppsLen=desc[indexPps].size;
111
112 ADM_info("Copy from annexB: Found sps=%d, pps=%d.\n",(int)spsLen,(int)ppsLen);
113 // Build extraData
114 myExtraLen=5+1+2+1+spsLen+1+2+1+ppsLen;
115 if(myExtra) delete [] myExtra;
116 myExtra=new uint8_t[myExtraLen];
117 uint8_t *ptr=myExtra;
118 uint8_t *sps=desc[indexSps].start;
119 *ptr++=1; // AVC version
120 *ptr++=sps[0]; // Profile
121 *ptr++=sps[1]; // Profile
122 *ptr++=sps[2]; // Level
123 *ptr++=0xff; // Nal size minus 1
124
125 *ptr++=0xe1; // SPS
126 *ptr++=(1+spsLen)>>8;
127 *ptr++=(1+spsLen)&0xff;
128 *ptr++=desc[indexSps].nalu;
129 memcpy(ptr,desc[indexSps].start,spsLen);
130 ptr+=spsLen;
131
132 *ptr++=0x1; // PPS
133 *ptr++=(1+ppsLen)>>8;
134 *ptr++=(1+ppsLen)&0xff;
135 *ptr++=desc[indexPps].nalu;
136 memcpy(ptr,desc[indexPps].start,ppsLen);
137 ptr+=ppsLen;
138
139 ADM_info("generated %d bytes of extradata.\n",(int)myExtraLen);
140 mixDump(myExtra, myExtraLen);
141 return true;
142 }
143
144 /**
145 * \fn extractExtraDataH264
146 */
extractExtraDataH264()147 bool ADM_videoStreamCopyFromAnnexB::extractExtraDataH264()
148 {
149 myBitstream=new ADMBitstream(ADM_COPY_FROM_ANNEX_B_SIZE);
150 myBitstream->data=buffer;
151
152 myExtra=NULL;
153 myExtraLen=0;
154 // Read the first keyframe in the range, it contains PPS & SPS
155 // Built avc-like atom from it.
156
157 /* We need the image at the start of the range as parameter sets
158 may change on the fly and we might get a disagreement between
159 the global header and in-band SPS & PPS from the start on if we
160 use the very first image in the stream.
161
162 Multiple SPS & PPS are not supported. */
163
164 ADMCompressedImage img;
165 img.data=buffer;
166 img.dataLength=0;
167 if(false==video_body->getDirectKeyFrameImageAtPts(startTimePts,&img))
168 {
169 ADM_warning("Cannot read the first keyframe image in the range\n");
170 return false;
171 }
172 myBitstream->len=img.dataLength;
173 if(extractExtraDataH264Internal())
174 return true;
175 // No SPS & PPS in the access unit? Fall back on the old behavior.
176 if(false==video_body->getDirectImageForDebug(0,&img))
177 {
178 ADM_warning("Cannot read first image\n");
179 return false;
180 }
181 myBitstream->len=img.dataLength;
182 return extractExtraDataH264Internal();
183 }
184
185 /**
186 *
187 * @param ptr
188 * @param naluType
189 * @param size
190 * @param data
191 * @return
192 */
writeNaluH265(uint8_t * ptr,NALU_descriptor * d)193 static uint8_t *writeNaluH265(uint8_t *ptr, NALU_descriptor *d)
194 {
195 *ptr++=(d->nalu>>1)&0x3f; // VPS, SPS, PPS, SEI. 0x20 0x21 0x22
196 *ptr++=0x00; // 1 NALU
197 *ptr++=0x01;
198 *ptr++=(d->size+1)>>8;
199 *ptr++=(d->size+1)&0xff;
200 *ptr++=d->nalu;
201 memcpy(ptr,d->start,d->size);
202 return ptr+d->size;
203 }
204 /**
205 * \fn extractExtraDataH265Internal
206 */
extractExtraDataH265Internal(void)207 bool ADM_videoStreamCopyFromAnnexB::extractExtraDataH265Internal(void)
208 {
209 NALU_descriptor desc[MAX_NALU_PER_CHUNK];
210
211 int nbNalu=ADM_splitNalu(myBitstream->data, myBitstream->data+myBitstream->len, MAX_NALU_PER_CHUNK, desc);
212
213 // The list of NALU we are interested in...
214 NALU_descriptor *vpsNalu,*ppsNalu,*spsNalu;
215
216 #define LoadNalu(x,y) x=ADM_findNaluH265(NAL_H265_##y,nbNalu,desc); \
217 if(!x) \
218 { \
219 ADM_error("Cannot find "#y); \
220 return false; \
221 }
222
223 #define NUMBER_OF_NALU_IN_EXTRADATA 3 // SEI ?
224 LoadNalu(vpsNalu,VPS);
225 LoadNalu(ppsNalu,PPS);
226 LoadNalu(spsNalu,SPS);
227
228 // Build extraData
229 myExtraLen=vpsNalu->size+ppsNalu->size+spsNalu->size+(7)*NUMBER_OF_NALU_IN_EXTRADATA+32;
230 if(myExtra) delete [] myExtra;
231 myExtra=new uint8_t[myExtraLen];
232 uint8_t *ptr=myExtra;
233
234
235 //8.3.3.1
236 //2
237 *ptr++=0x01; // HEVC version
238 uint8_t *s=spsNalu->start+2;
239 *ptr++=*s++; // 2: general_profile_space, 1: general_tier_flag, 5: general_profile_idc;
240 //4
241 *ptr++=*s++; //general_profile_compatibility_flags
242 *ptr++=*s++;
243 *ptr++=*s++;
244 *ptr++=*s++;
245 //6
246 *ptr++=0xb0; //general_constraint_indicator_flags
247 *ptr++=00;
248 *ptr++=00;
249 *ptr++=00;
250 *ptr++=00;
251 *ptr++=00;
252
253 //4
254 *ptr++=0x99; // general_level_idc
255 *ptr++=0xf0; // reserver + min_spatial_segmentation_idc
256 *ptr++=0x00; // min_spatial_segmentation_idc, continued;
257 *ptr++=0xfc; // parallelismType +111111
258
259 *ptr++=0xfd; // chromaFormat +111111
260 *ptr++=0xfa; // bitDepthLumaMinus8;+111111
261 *ptr++=0xfa; // bitDepthChromaMinus8;+111111
262 *ptr++=0; // Avg framerate
263 *ptr++=0; // Avg framerate
264
265 *ptr++=0x47; //2: constantFrameRate 3numTemporalLayers 1: temporalIdNested 2: lengthSizeMinusOne;
266
267 *ptr++=NUMBER_OF_NALU_IN_EXTRADATA; // num elem // SEI MISSING!!!!!# FIXME
268
269
270 ptr=writeNaluH265(ptr,vpsNalu);
271 ptr=writeNaluH265(ptr,spsNalu);
272 ptr=writeNaluH265(ptr,ppsNalu);
273
274 myExtraLen=(int)(ptr-myExtra);
275 ADM_info("generated %d bytes of extradata.\n",(int)myExtraLen);
276 mixDump(myExtra, myExtraLen);
277 return true;
278 }
279
280 /**
281 * \fn extractExtraDataH265
282 * We need to pack VPS/PPS/SPS MP4 style
283 *
284 * order should be VPS, SPS, PPS, SEI.
285 */
extractExtraDataH265()286 bool ADM_videoStreamCopyFromAnnexB::extractExtraDataH265()
287 {
288 myBitstream=new ADMBitstream(ADM_COPY_FROM_ANNEX_B_SIZE);
289 myBitstream->data=buffer;
290
291 myExtra=NULL;
292 myExtraLen=0;
293 // Read the first keyframe in the range, it contains PPS & SPS
294
295 ADMCompressedImage img;
296 img.data=buffer;
297 img.dataLength=0;
298 if(false==video_body->getDirectKeyFrameImageAtPts(startTimePts,&img))
299 {
300 ADM_warning("Cannot read first the first keyframe image in the range\n");
301 return false;
302 }
303 mixDump(img.data, 48);
304 myBitstream->len=img.dataLength;
305 if(extractExtraDataH265Internal())
306 return true;
307 // No PPS & SPS? Try the first frame of the first ref video.
308 if(false==video_body->getDirectImageForDebug(0,&img))
309 {
310 ADM_warning("Cannot read first image\n");
311 return false;
312 }
313 mixDump(img.data, 48);
314 myBitstream->len=img.dataLength;
315 return extractExtraDataH265Internal();
316 }
317 /**
318 \fn ctor
319 */
ADM_videoStreamCopyFromAnnexB(uint64_t startTime,uint64_t endTime)320 ADM_videoStreamCopyFromAnnexB::ADM_videoStreamCopyFromAnnexB(uint64_t startTime,uint64_t endTime):
321 ADM_videoStreamCopy(startTime,endTime)
322 {
323 ADM_info("AnnexB to iso filter\n");
324 _init=false;
325 h265=false;
326 aviInfo info;
327 video_body->getVideoInfo(&info);
328 if(isH264Compatible(info.fcc) )
329 {
330 if(!extractExtraDataH264())
331 ADM_warning("H264: Extract MP4 header from annexB failed\n");
332 else
333 _init=true;
334 }
335 else
336 if(isH265Compatible(info.fcc))
337 {
338 h265=true;
339 if(!extractExtraDataH265())
340 ADM_warning("H265: Extract MP4 header from annexB failed\n");
341 else
342 _init=true;
343 }
344 else
345 {
346 ADM_warning("Dont know how to process that\n");
347 }
348
349 rewind();
350
351 }
352 /**
353
354 \fn dtor
355
356 */
357
~ADM_videoStreamCopyFromAnnexB()358 ADM_videoStreamCopyFromAnnexB::~ADM_videoStreamCopyFromAnnexB()
359 {
360 ADM_info("Destroying AnnexB to iso filtet\n");
361 delete myBitstream;
362 myBitstream=NULL;
363 }
364
365 #define START_CODE_LEN 5
366
parseNalu(uint8_t * head,uint8_t * tail)367 static void parseNalu(uint8_t *head, uint8_t *tail)
368 {
369 printf("**** Parsing NALU : %d****",(int)(tail-head));
370 while(head<tail)
371 {
372 int32_t size=readBE32(head);
373 printf("[%02x] size=%d\n",head[START_CODE_LEN],size);
374 head+=size+START_CODE_LEN-1;
375 }
376 }
377 /**
378 \fn getPacket
379 */
380
getPacket(ADMBitstream * out)381 bool ADM_videoStreamCopyFromAnnexB::getPacket(ADMBitstream *out)
382 {
383 aprintf("-------%d--------\n",(int)currentFrame);
384 if(false==ADM_videoStreamCopy::getPacket(myBitstream)) return false;
385
386 int size;
387 if(h265)
388 size=ADM_convertFromAnnexBToMP4H265(myBitstream->data,myBitstream->len,out->data,out->bufferSize);
389 else
390 size=ADM_convertFromAnnexBToMP4(myBitstream->data,myBitstream->len,out->data,out->bufferSize);
391 out->len=size;
392 out->dts=myBitstream->dts;
393 out->pts=myBitstream->pts;
394 out->flags=myBitstream->flags;
395 //compactNalus(out);
396 #ifdef ANNEX_B_DEBUG
397 parseNalu(out->data,out->data+out->len);
398 #endif
399 return true;
400 }
401 /**
402 \fn getExtraData
403 */
getExtraData(uint32_t * extraLen,uint8_t ** extraData)404 bool ADM_videoStreamCopyFromAnnexB::getExtraData(uint32_t *extraLen, uint8_t **extraData)
405 {
406 *extraData=myExtra;
407 *extraLen=myExtraLen;
408 return true;
409 }
410
411 //---------------------
412
413
414 /**
415 \fn ctor
416 */
ADM_videoStreamCopyToAnnexB(uint64_t startTime,uint64_t endTime)417 ADM_videoStreamCopyToAnnexB::ADM_videoStreamCopyToAnnexB(uint64_t startTime,uint64_t endTime):
418 ADM_videoStreamCopy(startTime,endTime)
419 {
420 uint32_t extraLen;
421 uint8_t *extraData;
422
423 ADM_info("Iso to AnnexB filter\n");
424 myBitstream=new ADMBitstream(ADM_COPY_FROM_ANNEX_B_SIZE);
425 myBitstream->data=buffer;
426
427 myExtra=NULL;
428 myExtraLen=0;
429
430 AVCodec *codec=avcodec_find_decoder(AV_CODEC_ID_H264);
431 ADM_assert(codec);
432 AVCodecContext *context = avcodec_alloc_context3(codec);
433 ADM_assert(context);
434
435 aviInfo info;
436 video_body->getVideoInfo(&info);
437 context->width = info.width;
438 context->height = info.height;
439 context->pix_fmt = AV_PIX_FMT_YUV420P;
440
441 video_body->getExtraHeaderData(&extraLen,&extraData);
442 // duplicate extraData with malloc scheme, it will be freed by the bitstream filter
443 context->extradata=(uint8_t*)av_malloc(extraLen);
444 memcpy( context->extradata,extraData,extraLen);
445 context->extradata_size=extraLen;
446 codecContext=(void *)context;
447
448 // #warning Ok, should we open the codec by itself ?
449
450
451 AVBitStreamFilterContext *bsf;
452 bsf = av_bitstream_filter_init("h264_mp4toannexb");
453 ADM_assert(bsf);
454 bsfContext=bsf;
455 ADM_info("Copy to annexB initialized\n");
456
457 }
458 /**
459 *
460 */
~ADM_videoStreamCopyToAnnexB()461 ADM_videoStreamCopyToAnnexB:: ~ADM_videoStreamCopyToAnnexB()
462 {
463 ADM_info("Destroying iso to AnnexB filtet\n");
464 delete myBitstream;
465 myBitstream=NULL;
466
467 if(codecContext)
468 {
469 AVCodecContext *context=(AVCodecContext *)codecContext;
470 codecContext=NULL;
471 avcodec_close(context);
472 }
473
474
475 if(bsfContext)
476 {
477 AVBitStreamFilterContext *bsf=(AVBitStreamFilterContext *)bsfContext;
478 av_bitstream_filter_close(bsf);
479 bsfContext=NULL;
480 }
481
482 }
483 /**
484 *
485 * @param out
486 * @return
487 */
getPacket(ADMBitstream * out)488 bool ADM_videoStreamCopyToAnnexB::getPacket(ADMBitstream *out)
489 {
490 AVPacket pktOut;
491 bool keyFrame=false;
492
493 aprintf("-------%d--------\n",(int)currentFrame);
494 if(false==ADM_videoStreamCopy::getPacket(myBitstream)) return false;
495
496 // filter!
497 AVBitStreamFilterContext *bsf=(AVBitStreamFilterContext *)bsfContext;
498 AVCodecContext *context=(AVCodecContext *)codecContext;
499 if(myBitstream->flags & AVI_KEY_FRAME)
500 keyFrame=true;
501 int ret= av_bitstream_filter_filter(bsf, context, NULL,
502 &pktOut.data, &pktOut.size,
503 myBitstream->data, myBitstream->len,
504 keyFrame);
505
506 if(ret<0)
507 {
508 ADM_warning("Error while converting to annex B %d\n",ret);
509 return false;
510 }
511 memcpy(out->data,pktOut.data,pktOut.size);
512 out->len=pktOut.size;
513
514 if(ret>0)
515 {
516 av_freep(&(pktOut.data));
517 }
518
519
520
521 out->dts=myBitstream->dts;
522 out->pts=myBitstream->pts;
523 out->flags=myBitstream->flags;
524 return true;
525 }
526 /**
527 *
528 * @param out
529 * @return
530 */
getExtraData(uint32_t * extraLen,uint8_t ** extraData)531 bool ADM_videoStreamCopyToAnnexB::getExtraData(uint32_t *extraLen, uint8_t **extraData)
532 {
533 *extraLen=0;
534 *extraData=NULL;
535 return true; // no extra data in annex b
536 }
537
538
539 // EOF
540