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