1 /***************************************************************************
2 ADM_infoextractor
3 -------------------
4 - extract additionnal info from header (mp4/h263)
5 **************************************************************************/
6 /***************************************************************************
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 ***************************************************************************/
14
15 #ifdef _MSC_VER
16 # include <malloc.h>
17 #endif
18
19 #include "ADM_default.h"
20
21 extern "C"
22 {
23 #include "libavcodec/parser.h"
24 #include "libavcodec/avcodec.h"
25 #include "libavcodec/ff_spsinfo.h"
26 #include "libavutil/mem.h"
27 extern int ff_h264_info(AVCodecParserContext *parser, int ticksPerFrame, ffSpsInfo *ndo);
28 }
29
30 #include "ADM_Video.h"
31
32 #include "fourcc.h"
33 //#include "ADM_mp4.h"
34
35 #include "ADM_getbits.h"
36 #include "ADM_videoInfoExtractor.h"
37 #include "ADM_h264_tag.h"
38
39
40 //#define ANNEX_B_DEBUG
41
42 #if defined(ANNEX_B_DEBUG)
43 #define aprintf ADM_info
44 #define check isNalValid
45 #else
46 #define aprintf(...) {}
47 #define check(...) {}
48 #endif
49
50 #if 0
51 #define seiprintf ADM_info
52 #else
53 #define seiprintf(...) {}
54 #endif
55
56 extern bool ADM_findAnnexBStartCode(uint8_t *start, uint8_t *end, uint8_t *outstartcode,
57 uint32_t *offset, bool *fivebytes);
58
59 /**
60 \fn ADM_getH264SpsPpsFromExtraData
61 \brief Returns a copy of PPS/SPS extracted from extrdata
62 */
ADM_SPSannexBToMP4(uint32_t dataLen,uint8_t * incoming,uint32_t * outLen,uint8_t * outData)63 bool ADM_SPSannexBToMP4(uint32_t dataLen,uint8_t *incoming,
64 uint32_t *outLen, uint8_t *outData)
65 {
66 int p;
67 if(dataLen>200)
68 {
69 ADM_warning("SPS TOO LONG\n");
70 return false;
71 }
72 // 01
73 // 4d 40 1f ff
74 // e1 00 1b 67
75 // 4d 40 1f f6
76 // 02 80 2d
77
78 outData[0]=1;
79 outData[1]=0x4d;
80 outData[2]=0x40;
81 outData[3]=0x1f;
82 outData[4]=0xff;
83 outData[5]=0xe1; // 1 stream
84 outData[6]=0; // Len MSB
85 outData[7]=0; // Len LSB, should fit in 1 byte...
86 outData[8]=0x67; // Len LSB, should fit in 1 byte...
87 #if 1
88 memcpy(outData+9,incoming,dataLen);
89 p=dataLen;
90 #else
91 p=ADM_unescapeH264(dataLen,incoming,outData+9) ;
92 #endif
93 outData[7]=(p+1); // Len LSB, should fit in 1 byte...
94 outData[6]=(p+1)>>8; // MSB : And no, does not always fit
95 *outLen= p+9;
96 return true;
97 }
98
99 /**
100 \fn ADM_getNalSizeH264
101 \brief extract NALU length size from avcC header
102 */
ADM_getNalSizeH264(uint8_t * extra,uint32_t len)103 uint32_t ADM_getNalSizeH264(uint8_t *extra, uint32_t len)
104 {
105 if(len < 9)
106 {
107 ADM_warning("Invalid H.264 extradata length %u\n",len);
108 return 0;
109 }
110 if(extra[0] != 1)
111 {
112 ADM_warning("Invalid H.264 extradata\n");
113 return 0;
114 }
115 return (extra[4] & 3) + 1;
116 }
117
118 /**
119 \fn ADM_escapeH264
120 \brief Add escape stuff
121
122 */
ADM_escapeH264(uint32_t len,uint8_t * in,uint8_t * out)123 uint32_t ADM_escapeH264 (uint32_t len, uint8_t * in, uint8_t * out)
124 {
125 uint32_t outlen = 0;
126 uint8_t *tail = in + len;
127 if (len < 2)
128 return 0;
129 while (in < tail-1 )
130 {
131 if (!in[0] && !in[1])
132 {
133 out[0] = 0;
134 out[1] = 0;
135 out[2] = 3;
136 out += 3;
137 outlen += 3;
138 in += 2;
139 continue;
140 }
141 *out++ = *in++;
142 outlen++;
143 }
144 // copy last bytes
145 uint32_t left = tail - in;
146 memcpy (out, in, left);
147 outlen += left;
148 return outlen;
149
150 }
151 /**
152 \fn unescapeH264
153 \brief Remove escape stuff
154
155 */
ADM_unescapeH264(uint32_t len,uint8_t * in,uint8_t * out)156 uint32_t ADM_unescapeH264 (uint32_t len, uint8_t * in, uint8_t * out)
157 {
158 if (len < 3)
159 return 0;
160 uint8_t *offset = in;
161 uint8_t *firstOut=out;
162 uint32_t outlen = 0;
163 uint8_t *tail = in + len;
164 uint8_t *border=tail-3;
165
166 while (in < border)
167 {
168 if(in[1]) // cannot be 00 00 nor the next one
169 {
170 in += 2;
171 continue;
172 }
173 if(!in[0] && !in[1] && in[2] == 3)
174 {
175 uint32_t copy = in - offset + 2;
176 memcpy(out, offset, copy);
177 out += copy;
178 in += 3;
179 offset = in;
180 continue;
181 }
182 in++;
183 }
184 outlen=(int)(out-firstOut);
185 // copy last bytes
186 uint32_t left = tail - offset;
187 memcpy (out, offset, left);
188 outlen += left;
189 return outlen;
190
191 }
192 /**
193 \fn hrd
194 \brief decode hdr_parameters
195 */
hrd(getBits & bits)196 static int hrd(getBits &bits)
197 {
198 //ADM_warning("hdr not implemented\n");
199 int count = bits.getUEG();
200
201 bits.get(4); // bitRateScale
202 bits.get(4); // scale
203
204 for(int i = 0; i <= count; i++)
205 {
206 bits.getUEG(); // bitrate
207 bits.getUEG(); // sizeMinus1
208 bits.get(1); // cbrFlag
209 }
210
211 bits.get(5); // initialRemovalDelay
212
213 int removalDelay=bits.get(5);
214 int outputDelay=bits.get(5);
215
216 bits.get(5); // timeOffset
217
218 return removalDelay+outputDelay+2 ;
219 }
220 /**
221 \fn extractVUIInfo
222 */
extractVUIInfo(getBits & bits,ADM_SPSInfo * spsinfo)223 static uint8_t extractVUIInfo (getBits &bits, ADM_SPSInfo *spsinfo)
224 {
225 if (bits.get(1))
226 {
227 unsigned int aspect_ratio_information = bits.get( 8);
228
229 if (aspect_ratio_information == 255)
230 {
231 spsinfo->darNum = bits.get( 16);
232 spsinfo->darDen = bits.get( 16);
233 }
234 else if (aspect_ratio_information <
235 sizeof (pixel_aspect) / sizeof (*pixel_aspect))
236 {
237 spsinfo->darNum = pixel_aspect[aspect_ratio_information].num;
238 spsinfo->darDen = pixel_aspect[aspect_ratio_information].den;
239 }
240 }
241
242 if (bits.get(1)) // overscan
243 bits.get(1);
244
245 if (bits.get(1)) // vsp_color
246 {
247 bits.get( 4);
248
249 if (bits.get(1))
250 {
251 bits.get( 8);
252 bits.get( 8);
253 bits.get( 8);
254 }
255 }
256
257 if (bits.get(1)) // chroma
258 {
259 bits.getUEG();
260 bits.getUEG();
261 }
262
263 if (bits.get(1)) // timing
264 {
265 uint32_t timeinc_unit = bits.get( 32);
266 uint32_t timeinc_resolution = bits.get( 32);
267 uint32_t fixed_fps = bits.get(1);
268 ADM_info("Time unit =%d/%d\n",(int)timeinc_unit,(int)timeinc_resolution);
269 if (timeinc_unit > 0 && timeinc_resolution > 0)
270 spsinfo->fps1000 = (uint32_t) (((float) timeinc_resolution / (float) timeinc_unit) * 1000);
271 /* No!
272 if (fixed_fps)
273 *fps1000 /= 2;
274 */
275 }
276 uint32_t f=0;
277 spsinfo->CpbDpbToSkip=0;
278 if(bits.get(1)) // nal_hrd_param
279 {
280 f++;
281 spsinfo->CpbDpbToSkip+=hrd(bits);
282 }
283 if(bits.get(1)) // vcl_hrd_param
284 {
285 f++;
286 spsinfo->CpbDpbToSkip+=hrd(bits);
287 }
288 if(f) bits.get(1); // low delay flag
289
290
291 spsinfo->hasStructInfo=bits.get(1) | spsinfo->CpbDpbToSkip;
292 // Has struct info in SEI, see D2.2
293
294 return 1;
295 }
296 /**
297 \fn decodeOnMatrix
298 \brief borrowed from ffmpeg
299 */
decodeOneMatrix(int count,getBits & bits)300 bool decodeOneMatrix(int count,getBits &bits)
301 {
302 if(!bits.get(1))
303 {
304 return true;
305 }
306
307 int i, last = 8, next = 8;
308 for(i=0;i<count;i++)
309 {
310 if(next)
311 next = (last + bits.getUEG()) & 0xff;
312 if(!i && !next)
313 { /* matrix not written, we use the preset one */
314 return true;
315 }
316 //last = factors[scan[i]] = next ? next : last;
317 }
318 return true;
319
320 }
321 /**
322 \fn decodeScalingMatrices
323 */
decodeScalingMatrices(getBits & bits)324 bool decodeScalingMatrices(getBits &bits)
325 {
326 decodeOneMatrix(16,bits);
327 decodeOneMatrix(16,bits);
328 decodeOneMatrix(16,bits);
329 decodeOneMatrix(16,bits);
330 decodeOneMatrix(16,bits);
331 decodeOneMatrix(16,bits);
332 decodeOneMatrix(64,bits);
333 decodeOneMatrix(64,bits);
334 return true;
335 }
336
337 /**
338 \fn extractSPSInfo
339 \brief Extract info from H264 SPS
340 See 7.3.2.1 of 14496-10
341 */
extractSPSInfo_internal(uint8_t * data,uint32_t len,ADM_SPSInfo * spsinfo)342 uint8_t extractSPSInfo_internal (uint8_t * data, uint32_t len, ADM_SPSInfo *spsinfo)
343 {
344
345 uint32_t profile, constraint, level, pic_order_cnt_type, w, h, mbh,
346 frame_mbs_only;
347 uint32_t frame_cropping_flag;
348 uint32_t chroma_format_idc = 1; // this defaults to 1 when it's missing
349 uint32_t separate_colour_plane_flag = 0;
350 uint32_t chroma_array_type = 0;
351 uint8_t *buf = new uint8_t[len];
352 uint32_t outlen;
353 uint32_t id, dum;
354
355 ADM_assert(spsinfo);
356 memset(spsinfo,0,sizeof(*spsinfo));
357
358
359 outlen = ADM_unescapeH264 (len, data, buf);
360 getBits bits(outlen,buf);
361 delete [] buf;
362
363 profile = bits.get(8);
364 constraint = bits.get( 8) >> 5;
365 level = bits.get( 8);
366 id = bits.getUEG(); // Seq parameter set id
367 printf ("[H264]Profile : %u, Level :%u, SPSid:%u\n", profile, level, id);
368 if (profile >= 100) // ?? Borrowed from H264.C/FFMPEG
369 {
370 printf ("[H264]Warning : High profile\n");
371 chroma_format_idc = bits.getUEG();
372 if (chroma_format_idc == 3) //chroma_format_idc
373 separate_colour_plane_flag = bits.get(1); //residual_color_transform_flag
374 bits.getUEG(); //bit_depth_luma_minus8
375 bits.getUEG(); //bit_depth_chroma_minus8
376 bits.get(1); // Transform bypass
377 if (bits.get(1)) // Scaling matrix
378 {
379 printf ("[H264] Scaling matrix present\n");
380 decodeScalingMatrices(bits);
381 }
382 }
383
384 if ( separate_colour_plane_flag == 0 )
385 chroma_array_type = chroma_format_idc;
386
387 dum = bits.getUEG(); // log2_max_frame_num_minus4
388 printf ("[H264]Log2maxFrame-4:%u\n", dum);
389 pic_order_cnt_type = bits.getUEG();
390 printf ("[H264]Pic Order Cnt Type:%u\n", pic_order_cnt_type);
391 if (!pic_order_cnt_type) // pic_order_cnt_type
392 {
393 dum = bits.getUEG(); //log2_max_pic_order_cnt_lsb_minus4
394 printf ("[H264]Log2maxPix-4:%u\n", dum);
395 }
396 else
397 {
398 if (pic_order_cnt_type == 1)
399 {
400 bits.get(1); //delta_pic_order_always_zero_flag
401 bits.getSEG(); //offset_for_non_ref_pic
402 bits.getSEG(); // offset_for_top_to_bottom_field
403 int i = bits.getUEG() ; //num_ref_frames_in_pic_order_cnt_cycle
404
405 for (int j = 0; j < i; j++)
406 {
407 bits.getSEG();
408 }
409 }
410 else if (pic_order_cnt_type != 2)
411 {
412 printf ("Error in SPS\n");
413 return 0;
414 }
415 }
416 dum = bits.getUEG(); //num_ref_frames
417 printf ("[H264] # of ref frames : %u\n", dum);
418 bits.get(1); // gaps_in_frame_num_value_allowed_flag
419 w = bits.getUEG() + 1; //pic_width_in_mbs_minus1
420
421 mbh = bits.getUEG() + 1;
422 frame_mbs_only = bits.get(1);
423 h = (2 - frame_mbs_only) * mbh; //pic_height_in_mbs_minus1
424
425 printf ("[H264] Width in mb -1 :%d\n", w);
426 printf ("[H264] Height in mb -1 :%d\n", h);
427
428 spsinfo->width = w * 16;
429 spsinfo->height = h * 16;
430
431 if (!frame_mbs_only)
432 bits.get(1);
433
434 bits.get(1);
435
436 frame_cropping_flag = bits.get(1);
437 if (frame_cropping_flag)
438 {
439 // The tests could probably be done more simply but the following is per the spec.
440 uint32_t cl, cr, ct, cb;
441 int cux = 1; // x units
442 int cuy = 2 - frame_mbs_only; // y units
443 if ( chroma_array_type > 0 ) {
444 switch( chroma_format_idc ) {
445 case 1:
446 cux = 2;
447 cuy = 2 * ( 2 - frame_mbs_only );
448 break;
449 case 2:
450 cux = 2;
451 cuy = 1 * ( 2 - frame_mbs_only );
452 break;
453 case 3:
454 cux = 1;
455 cuy = 1 * ( 2 - frame_mbs_only );
456 break;
457 }
458 }
459 cl = bits.getUEG() * cux;
460 cr = bits.getUEG() * cux;
461 ct = bits.getUEG() * cuy;
462 cb = bits.getUEG() * cuy;
463 spsinfo->width -= cl; // reduce dims based on crop values
464 spsinfo->width -= cr;
465 spsinfo->height -= ct;
466 spsinfo->height -= cb;
467 printf ("[H264] Has cropping of l:%d r:%d t:%d b:%d\n", cl, cr, ct, cb);
468 }
469
470 if (bits.get(1))
471 {
472 extractVUIInfo (bits, spsinfo);
473 // printf ("[H264] Fps %" LU ", a.r. %" LU ",%" LU "\n", spsinfo->fps1000, spsinfo->darNum, spsinfo->darDen);
474 }
475 else
476 {
477 printf ("[H264] Unknown FPS, setting 25\n");
478 spsinfo->fps1000 = 25000;
479 }
480 return 1;
481 }
482
483 /**
484 \fn getInfoFromSei
485 \brief Get SEI type, decode recovery point
486 \return 0: failure, 1: recovery, 2: unregistered user data, 3: both
487 */
488 enum {
489 ADM_H264_SEI_TYPE_OTHER = 0,
490 ADM_H264_SEI_TYPE_USER_DATA_UNREGISTERED = 1,
491 ADM_H264_SEI_TYPE_RECOVERY_POINT = 2
492 };
493
getInfoFromSei(uint32_t nalSize,uint8_t * org,uint32_t * recoveryLength,uint32_t * unregistered)494 static int getInfoFromSei(uint32_t nalSize, uint8_t *org, uint32_t *recoveryLength, uint32_t *unregistered)
495 {
496 int originalNalSize=nalSize+16;
497 uint8_t *payloadBuffer=(uint8_t *)malloc(originalNalSize+AV_INPUT_BUFFER_PADDING_SIZE);
498 memset(payloadBuffer,0,originalNalSize+AV_INPUT_BUFFER_PADDING_SIZE);
499 uint8_t *payload=payloadBuffer;
500 int r=ADM_H264_SEI_TYPE_OTHER;
501 nalSize=ADM_unescapeH264(nalSize,org,payload);
502 if(nalSize>originalNalSize)
503 {
504 ADM_warning("NAL is way too big : %d, while we expected %d at most\n",nalSize,originalNalSize);
505 free(payloadBuffer);
506 return r;
507 }
508
509 uint8_t *tail=payload+nalSize;
510
511 while(payload+2<tail)
512 {
513 uint32_t sei_type=0,sei_size=0;
514 while(payload[0]==0xff)
515 {
516 sei_type+=0xff;payload++;
517 if(payload+2>=tail)
518 {
519 seiprintf("Not enough data.\n");
520 goto abtSei;
521 }
522 }
523 sei_type+=payload[0];payload++;
524 if(payload>=tail)
525 {
526 seiprintf("No data left after decoding SEI type.\n");
527 goto abtSei;
528 }
529 while(payload[0]==0xff)
530 {
531 sei_size+=0xff;payload++;
532 if(payload+1>=tail)
533 {
534 seiprintf("Not enough data left after decoding SEI size.\n");
535 goto abtSei;
536 }
537 }
538 sei_size+=payload[0];payload++;
539 seiprintf("Type: %u size: %u remaining: %d\n",sei_type,sei_size,tail-payload);
540 if(payload+sei_size>tail)
541 {
542 seiprintf("Not enough data.\n");
543 break;
544 }
545 switch(sei_type)
546 {
547 case 5: // Unregistered user data
548 {
549 if(!unregistered) break;
550 if(sei_size<16)
551 {
552 ADM_info("User data too short: %u\n",sei_size);
553 break;
554 }
555 char *udata=(char *)malloc(16+sei_size+1);
556 getBits bits(sei_size,payload);
557 for(uint32_t i=0; i<sei_size; i++)
558 udata[i]=bits.get(8);
559 udata[sei_size]=0;
560 int build;
561 if(1!=sscanf(udata+16,"x264 - core %d",&build))
562 {
563 ADM_info("Unregistered user data doesn't match the one expected for x264\n");
564 mixDump((uint8_t *)udata,sei_size);
565 break;
566 }
567 free(udata);
568 *unregistered=sei_size;
569 ADM_info("Found unregistered user data from x264 build %d, size: %u\n",build,sei_size);
570 r |= ADM_H264_SEI_TYPE_USER_DATA_UNREGISTERED;
571 break;
572 }
573 case 6: // Recovery point
574 {
575 if(!recoveryLength) break;
576 getBits bits(sei_size,payload);
577 int distance=bits.getUEG();
578 if(distance<0)
579 {
580 ADM_warning("Invalid UE golomb code encountered while decoding recovery distance.\n");
581 break;
582 }
583 seiprintf("Recovery distance: %d\n",distance);
584 *recoveryLength=distance;
585 r |= ADM_H264_SEI_TYPE_RECOVERY_POINT;
586 break;
587 }
588 default:break;
589 }
590 payload+=sei_size;
591 }
592 abtSei:
593 free(payloadBuffer);
594 return r;
595 }
596 /**
597 \fn getNalType
598 \brief Return the slice type. The stream is escaped by the function. If recovery==0
599 or frame_num==0 I is considered IDR else as P.
600 */
getNalType(uint8_t * head,uint8_t * tail,uint32_t * flags,ADM_SPSInfo * sps,int * poc_lsb,int recovery)601 static bool getNalType (uint8_t *head, uint8_t *tail, uint32_t *flags, ADM_SPSInfo *sps, int *poc_lsb, int recovery)
602 {
603 if(tail<=head)
604 return false;
605 uint8_t *out=(uint8_t *)malloc(tail-head+AV_INPUT_BUFFER_PADDING_SIZE);
606 memset(out,0,tail-head+AV_INPUT_BUFFER_PADDING_SIZE);
607 int size=ADM_unescapeH264(tail-head,head,out);
608
609 getBits bits(size,out);
610 uint32_t sliceType;
611 uint32_t fieldFlags=0;
612 int frame = -1;
613 *poc_lsb = -1;
614
615 bits.getUEG(); // first mb in slice
616 sliceType = bits.getUEG31(); // get_ue_golomb_31??
617 if(sps && sps->log2MaxFrameNum > 3 && sps->log2MaxFrameNum < 17) // sanity check
618 {
619 bits.getUEG(); // skip PPS id
620 frame = bits.get(sps->log2MaxFrameNum);
621 if(!sps->frameMbsOnlyFlag && bits.get(1))
622 {
623 fieldFlags |= AVI_FIELD_STRUCTURE;
624 if(bits.get(1))
625 fieldFlags |= AVI_BOTTOM_FIELD;
626 else
627 fieldFlags |= AVI_TOP_FIELD;
628 }
629 if(sps->hasPocInfo)
630 {
631 if(*flags & AVI_IDR_FRAME) // from NAL
632 bits.getUEG(); // skip idr_pic_id
633 *poc_lsb = bits.get(sps->log2MaxPocLsb);
634 }
635 }
636 if (sliceType > 9)
637 {
638 ADM_warning ("Weird Slice %d\n", sliceType);
639 free(out);
640 return false;
641 }
642 if (sliceType > 4)
643 sliceType -= 5;
644
645 switch(sliceType)
646 {
647 case 3:
648 case 0: *flags = AVI_P_FRAME;break;
649 case 1: *flags = AVI_B_FRAME;break;
650 case 2: case 4:
651 if((*flags & AVI_KEY_FRAME) && !sps)
652 break; // trust NAL when we cannot verify
653 if(!recovery || !frame)
654 *flags = AVI_KEY_FRAME;
655 else
656 *flags = AVI_P_FRAME;
657 if(!frame)
658 *flags |= AVI_IDR_FRAME;
659 break;
660
661 }
662 *flags |= fieldFlags;
663 free(out);
664 return true;
665 }
666
667 /**
668 \fn extractH264FrameType
669 \brief Parse access unit in buffer of size len, return frametype in flags (KEY/P/B).
670 nalSize should be either the NALU length size value retrieved from extradata or 0 for autodetect.
671 If ADM_SPSInfo is provided, return POC LSB or -1 if implicit or on error.
672 Return value: 1 on success, 0 on failure.
673 To be used only with AVCC (mkv/mp4) nal type (i.e. no startcode)
674 */
extractH264FrameType(uint8_t * buffer,uint32_t len,uint32_t nalSize,uint32_t * flags,int * pocLsb,ADM_SPSInfo * sps,uint32_t * extRecovery)675 uint8_t extractH264FrameType(uint8_t *buffer, uint32_t len, uint32_t nalSize, uint32_t *flags, int *pocLsb, ADM_SPSInfo *sps, uint32_t *extRecovery)
676 {
677 uint8_t *head = buffer, *tail = buffer + len;
678 uint8_t stream;
679 uint32_t i, length = 0;
680
681 if(!nalSize || nalSize > 4)
682 { // Try to detect number of bytes used to code NAL length. Shaky.
683 nalSize = 4;
684 for(i = 0; i < nalSize; i++)
685 {
686 length = (length << 8) + head[i];
687 if(i && length > len)
688 {
689 nalSize = i;
690 break;
691 }
692 }
693 }
694 uint32_t recovery=0xff;
695 int p=-1;
696
697 *flags=0;
698 while (head + nalSize < tail)
699 {
700 length = 0;
701 for(i = 0; i < nalSize; i++)
702 length = (length << 8) + head[i];
703 if (length > len)// || length < 2)
704 {
705 ADM_warning ("Warning , incomplete nal (%u/%u),(%0x/%0x)\n", length, len, length, len);
706 *flags = 0;
707 return 0;
708 }
709 head += nalSize; // Skip nal lenth
710 len = (len > nalSize)? len - nalSize : 0;
711 int ref=(*(head)>>5) & 3;
712 stream = *(head) & 0x1F;
713
714 switch (stream)
715 {
716 case NAL_SEI:
717 {
718 int sei=getInfoFromSei(length-1, head+1, &recovery, NULL);
719 if(extRecovery)
720 {
721 if(sei & ADM_H264_SEI_TYPE_RECOVERY_POINT)
722 *extRecovery=recovery;
723 else
724 recovery=*extRecovery;
725 }
726 }
727 break;
728 case NAL_SPS:
729 case NAL_PPS:
730 case NAL_AU_DELIMITER:
731 case NAL_FILLER:
732 break;
733 case NAL_IDR:
734 *flags = AVI_KEY_FRAME + AVI_IDR_FRAME;
735 if(!getNalType(head+1,head+length,flags,sps,&p,recovery))
736 return 0;
737 if(sps && !(*flags & AVI_IDR_FRAME))
738 {
739 ADM_warning("Mismatched frame (flags: %d) in IDR NAL unit!\n",*flags);
740 *flags &= ~AVI_B_FRAME;
741 *flags |= AVI_KEY_FRAME; // FIXME
742 }
743 if(pocLsb)
744 *pocLsb=p;
745 return 1;
746 case NAL_NON_IDR:
747 if(!getNalType(head+1,head+length,flags,sps,&p,recovery))
748 return 0;
749 if(!ref && (*flags & AVI_B_FRAME))
750 *flags |= AVI_NON_REF_FRAME;
751 if(pocLsb)
752 *pocLsb=p;
753 return 1;
754 default:
755 ADM_warning ("unknown nal ??0x%x\n", stream);
756 break;
757 }
758 head+=length;
759 len = (len > length)? len - length : 0;
760 }
761 ADM_warning ("No stream\n");
762 return 0;
763 }
764
765 /**
766 \fn extractH264FrameType_startCode
767 \brief return frametype in flags (KEY_FRAME or 0).
768 To be used only with avi / mpeg TS nal type
769 (i.e. with startcode 00 00 00 01)
770 */
extractH264FrameType_startCode(uint8_t * buffer,uint32_t len,uint32_t * flags,int * pocLsb,ADM_SPSInfo * sps,uint32_t * extRecovery)771 uint8_t extractH264FrameType_startCode(uint8_t *buffer, uint32_t len, uint32_t *flags, int *pocLsb, ADM_SPSInfo *sps, uint32_t *extRecovery)
772 {
773 uint8_t *head = buffer, *tail = buffer + len;
774 uint8_t stream;
775 uint32_t hnt=0xffffffff;
776 uint32_t recovery=0xff;
777 int counter = 0, length = 0;
778 int ref = 0, p = -1;
779 bool last = false;
780
781 *flags = 0;
782
783 while (head + 2 < tail)
784 {
785 // Search startcode
786 hnt = (hnt << 8) + head[0];
787 if((hnt & 0xffffff) != 1)
788 {
789 head++;
790 if(head + 2 < tail)
791 continue;
792 if(!counter) break;
793 last = true;
794 length = head - buffer + 2;
795 }
796 int prevNaluRefIdc = 0;
797 uint8_t prevNaluType = 0;
798 if(!last)
799 {
800 head++;
801 counter++;
802 if(counter > 1)
803 length = head - buffer - 3; // 3 bytes start code length no matter zero-prefixed or not
804 prevNaluRefIdc = (*head >> 5) & 3;
805 prevNaluType = *(head++) & 0x1f;
806 if(!length)
807 {
808 buffer = head;
809 ref = prevNaluRefIdc;
810 stream = prevNaluType;
811 continue;
812 }
813 }
814 switch (stream)
815 {
816 case NAL_SEI:
817 {
818 int sei=getInfoFromSei(length, buffer, &recovery, NULL);
819 if(extRecovery)
820 {
821 if(sei & ADM_H264_SEI_TYPE_RECOVERY_POINT)
822 *extRecovery=recovery;
823 else
824 recovery=*extRecovery;
825 }
826 }
827 break;
828 case NAL_SPS: case NAL_PPS: case NAL_FILLER: case NAL_AU_DELIMITER: break;
829 case NAL_IDR:
830 *flags = AVI_KEY_FRAME + AVI_IDR_FRAME;
831 if(!getNalType(buffer, buffer+length, flags, sps, &p, recovery))
832 return 0;
833 if(sps && !(*flags & AVI_IDR_FRAME))
834 {
835 ADM_warning("Mismatched frame (flags: %d) in IDR NAL unit!\n",*flags);
836 *flags &= ~AVI_B_FRAME;
837 *flags |= AVI_KEY_FRAME; // FIXME
838 }
839 if(pocLsb)
840 *pocLsb=p;
841 return 1;
842 case NAL_NON_IDR:
843 if(!getNalType(buffer, buffer+length, flags, sps, &p, recovery))
844 return 0;
845 if(!ref && (*flags & AVI_B_FRAME))
846 *flags |= AVI_NON_REF_FRAME;
847 if(pocLsb)
848 *pocLsb=p;
849 return 1;
850 default:
851 ADM_warning("Unknown NAL type ??0x%x\n", stream);
852 break;
853 }
854 buffer = head;
855 ref = prevNaluRefIdc;
856 stream = prevNaluType;
857 }
858 printf ("No stream\n");
859 return 0;
860 }
861
862 /**
863 * \fn extractH264SEI
864 * \brief If present, copy SEI containing x264 version info from access unit src to dest
865 */
extractH264SEI(uint8_t * src,uint32_t inlen,uint32_t nalSize,uint8_t * dest,uint32_t bufsize,uint32_t * outlen)866 bool extractH264SEI(uint8_t *src, uint32_t inlen, uint32_t nalSize, uint8_t *dest, uint32_t bufsize, uint32_t *outlen)
867 {
868 uint8_t *tail = src, *head = src + inlen;
869 uint8_t stream;
870 uint32_t i, length = 0;
871
872 if(!nalSize || nalSize > 4)
873 { // Try to detect NAL length size.
874 nalSize = 4;
875 for(i = 0; i < nalSize; i++)
876 {
877 length = (length << 8) + tail[i];
878 if(i && length > inlen)
879 {
880 nalSize = i;
881 break;
882 }
883 }
884 }
885 uint32_t unregistered = 0;
886
887 while(tail + nalSize < head)
888 {
889 length = 0;
890 for(i = 0; i < nalSize; i++)
891 length = (length << 8) + tail[i];
892 if(length > inlen)
893 {
894 ADM_warning ("Incomplete NALU, length: %u, available: %u\n", length, inlen);
895 return false;
896 }
897 tail += nalSize;
898 inlen = (inlen > nalSize)? inlen - nalSize : 0;
899 stream = *(tail) & 0x1f;
900
901 if(stream == NAL_SEI)
902 {
903 if(getInfoFromSei(length-1,tail+1,NULL,&unregistered) & ADM_H264_SEI_TYPE_USER_DATA_UNREGISTERED)
904 {
905 uint32_t l = nalSize + length;
906 if(l > bufsize)
907 {
908 ADM_warning("Insufficient destination buffer, need %u, got %u\n",l,bufsize);
909 return false;
910 }
911 if(dest)
912 memcpy(dest,tail-nalSize,l); // what about emulation prevention bytes??
913 if(outlen)
914 *outlen = l;
915 return true;
916 }
917 }
918 tail += length;
919 inlen = (inlen > length)? inlen - length : 0;
920 }
921
922 return false;
923 }
924
925
926
927 /**
928 \fn extractSPSInfo_mp4Header
929 \brief Only works for mp4 style headers i.e. begins by 0x01
930 */
extractSPSInfo_mp4Header(uint8_t * data,uint32_t len,ADM_SPSInfo * spsinfo)931 bool extractSPSInfo_mp4Header (uint8_t * data, uint32_t len, ADM_SPSInfo *spsinfo)
932 {
933 bool r=false;
934
935 // duplicate
936 int myLen=len+AV_INPUT_BUFFER_PADDING_SIZE;
937 uint8_t *myData=new uint8_t[myLen];
938 memset(myData,0x2,myLen);
939 memcpy(myData,data,len);
940 myData[len]=0; // stop ff_h264_decode_extradata() from trying to parse the remaining buffer content as PPS
941
942 // 1-Create parser
943 AVCodecParserContext *parser=av_parser_init(AV_CODEC_ID_H264);
944 AVCodecContext *ctx=NULL;
945 AVCodec *codec=NULL;
946 uint8_t *d=NULL;
947
948 if(!parser)
949 {
950 ADM_error("cannot create h264 parser\n");
951 goto theEnd;
952 }
953 ADM_info("Parser created\n");
954 codec=avcodec_find_decoder(AV_CODEC_ID_H264);
955 if(!codec)
956 {
957 ADM_error("cannot create h264 codec\n");
958 goto theEnd;
959 }
960 ADM_info("Codec created\n");
961 ctx=avcodec_alloc_context3(codec);
962 if (avcodec_open2(ctx, codec, NULL) < 0)
963 {
964 ADM_error("cannot create h264 context\n");
965 goto theEnd;
966 }
967
968 ADM_info("Context created, ticks_per_frame = %d\n",ctx->ticks_per_frame);
969 //2- Parse, let's add SPS prefix + Filler postfix to make life easier for libavcodec parser
970 ctx->extradata=myData;
971 ctx->extradata_size=len;
972 {
973 uint8_t *outptr=NULL;
974 int outsize=0;
975
976 int used=av_parser_parse2(parser, ctx, &outptr, &outsize, d, 0, 0, 0,0);
977 printf("Used bytes %d/%d (+5)\n",used,len);
978 if(!used)
979 {
980 //ADM_warning("Failed to extract SPS info\n"); // it ain't necessarily so
981 // goto theEnd;
982 }
983 }
984 // Size is not supposed to be set in AVCodecContext after parsing
985 //ADM_info("Width : %d\n",ctx->width);
986 //ADM_info("Height : %d\n",ctx->height);
987 {
988 ffSpsInfo nfo;
989 if(!ff_h264_info(parser,ctx->ticks_per_frame,&nfo))
990 {
991 ADM_error("Cannot get sps info from lavcodec\n");
992 r=false;
993 goto theEnd;
994 }
995 ADM_info("Width2 : %d\n",nfo.width);
996 ADM_info("Height2: %d\n",nfo.height);
997 #define CPY(x) spsinfo->x=nfo.x
998 CPY(width);
999 CPY(height);
1000 CPY(fps1000);
1001 CPY(hasStructInfo);
1002 CPY(hasPocInfo);
1003 CPY(CpbDpbToSkip);
1004 CPY(log2MaxFrameNum);
1005 CPY(log2MaxPocLsb);
1006 CPY(frameMbsOnlyFlag);
1007 CPY(darNum);
1008 CPY(darDen);
1009 CPY(refFrames);
1010 r=true;
1011 }
1012 // cleanup
1013 theEnd:
1014 if(ctx)
1015 {
1016 avcodec_close(ctx);
1017
1018 av_free(ctx);
1019 }
1020 if(parser)
1021 av_parser_close(parser);
1022
1023 delete [] myData;
1024
1025 return r;
1026 }
1027
1028 /**
1029 \fn getRawH264SPS
1030 \brief Find the first SPS in mp4 style buffer and copy it to dest, return SPS length.
1031 */
getRawH264SPS(uint8_t * data,uint32_t len,uint32_t nalSize,uint8_t * dest,uint32_t maxsize)1032 uint32_t getRawH264SPS(uint8_t *data, uint32_t len, uint32_t nalSize, uint8_t *dest, uint32_t maxsize)
1033 {
1034 if(!dest || !maxsize)
1035 return 0;
1036
1037 uint8_t *head=data, *tail=data+len;
1038 uint8_t stream;
1039
1040 uint32_t i, length=0;
1041 if(!nalSize || nalSize > 4)
1042 { // Try to detect NAL length size.
1043 nalSize = 4;
1044 for(i = 0; i < nalSize; i++)
1045 {
1046 length = (length << 8) + head[i];
1047 if(i && length > len)
1048 {
1049 nalSize = i;
1050 break;
1051 }
1052 }
1053 }
1054
1055 while(head + nalSize < tail)
1056 {
1057 length=0;
1058 for(i = 0; i < nalSize; i++)
1059 length = (length << 8) + head[i];
1060 if(length > len)
1061 {
1062 ADM_warning ("Incomplete NALU, length: %u, available: %u\n", length, len);
1063 return 0;
1064 }
1065 head += nalSize;
1066 len = (len>nalSize)? len-nalSize : 0;
1067 stream = *head & 0x1F;
1068
1069 if(stream == NAL_SPS)
1070 {
1071 if(length>maxsize)
1072 {
1073 ADM_warning("Buffer too small for SPS: need %u got %u\n",length,maxsize);
1074 return 0;
1075 }
1076 memcpy(dest,head,length);
1077 return length;
1078 }
1079 head += length;
1080 len = (len>length)? len-length : 0;
1081 }
1082
1083 return 0;
1084 }
1085
1086 /**
1087 \fn getRawH264SPS_startCode
1088 \brief Find the first SPS in AnnexB style buffer and copy it to dest, return SPS length.
1089 */
getRawH264SPS_startCode(uint8_t * data,uint32_t len,uint8_t * dest,uint32_t maxsize)1090 uint32_t getRawH264SPS_startCode(uint8_t *data, uint32_t len, uint8_t *dest, uint32_t maxsize)
1091 {
1092 if(!dest || !maxsize)
1093 return 0;
1094
1095 uint8_t *head = data;
1096 uint8_t *tail = head + len;
1097 uint8_t stream = 0;
1098 uint32_t hnt = 0xffffffff;
1099 int counter = 0, length = 0;
1100 bool last = false;
1101 #define MAX_NALU_TO_CHECK 4
1102 while(head + 2 < tail)
1103 {
1104 if(counter > MAX_NALU_TO_CHECK)
1105 return 0;
1106
1107 hnt = (hnt << 8) + head[0];
1108 if((hnt & 0xffffff) != 1)
1109 {
1110 head++;
1111 if(head + 2 < tail)
1112 continue;
1113 if(!counter) break;
1114 last = true;
1115 }
1116 length = head - data + 2;
1117 uint8_t prevNaluType = 0;
1118 if(!last)
1119 {
1120 head++;
1121 counter++;
1122 if(counter > 1)
1123 length = head - data - 3; // likely one zerobyte too much, harmless
1124 prevNaluType = *head & 0x1f;
1125 if(!length)
1126 {
1127 data = head;
1128 stream = prevNaluType;
1129 continue;
1130 }
1131 }
1132 if(stream == NAL_SPS)
1133 {
1134 if(length>maxsize)
1135 {
1136 ADM_warning("Buffer too small for SPS: need %d, got %u\n",length,maxsize);
1137 return 0;
1138 }
1139 memcpy(dest,data,length);
1140 return length;
1141 }
1142 data = head++;
1143 stream = prevNaluType;
1144 }
1145 #undef MAX_NALU_TO_CHECK
1146 return 0;
1147 }
1148
1149 /**
1150 \fn extractSPSInfoFromData
1151 \brief Decode raw SPS data
1152 */
extractSPSInfoFromData(uint8_t * data,uint32_t length,ADM_SPSInfo * spsinfo)1153 bool extractSPSInfoFromData(uint8_t *data, uint32_t length, ADM_SPSInfo *spsinfo)
1154 {
1155 uint32_t myExtraLen=length+8;
1156 uint8_t *myExtra=new uint8_t[myExtraLen];
1157 memset(myExtra,0,myExtraLen);
1158 uint8_t *p=myExtra;
1159 // Create fake avcC extradata
1160 *p++=1; // AVC version
1161 *p++=data[1]; // Profile
1162 *p++=data[2]; // Profile compatibility
1163 *p++=data[3]; // Level
1164 *p++=0xff; // Nal size minus 1
1165 *p++=0xe1; // 1x SPS
1166 *p++=length>>8;
1167 *p++=length&0xFF;
1168 memcpy(p,data,length);
1169
1170 bool r = extractSPSInfo_mp4Header(myExtra,myExtraLen,spsinfo);
1171
1172 delete [] myExtra;
1173 myExtra=NULL;
1174
1175 return r;
1176 }
1177
1178 /**
1179 \fn extractSPSInfo2
1180 \brief Same as extractSPSInfo, but using libavcodec
1181 */
extractSPSInfo_lavcodec(uint8_t * data,uint32_t len,ADM_SPSInfo * spsinfo)1182 uint8_t extractSPSInfo_lavcodec (uint8_t * data, uint32_t len, ADM_SPSInfo *spsinfo)
1183 {
1184 if(data[0]==1) return extractSPSInfo_mp4Header(data,len,spsinfo);
1185
1186 ADM_info("Incoming SPS info\n");
1187 mixDump(data,len);
1188
1189 ADM_info("converted SPS info\n");
1190
1191 uint32_t converted;
1192 uint8_t buffer[256];
1193 if(! ADM_SPSannexBToMP4(len,data,&converted,buffer))
1194 {
1195 ADM_warning("Cannot convert SPS\n");
1196 return false;
1197 }
1198 mixDump(buffer,converted);
1199 return extractSPSInfo_mp4Header(buffer,converted,spsinfo) ;
1200
1201 }
1202
extractSPSInfo(uint8_t * data,uint32_t len,ADM_SPSInfo * spsinfo)1203 bool extractSPSInfo (uint8_t * data, uint32_t len, ADM_SPSInfo *spsinfo)
1204 {
1205 #define DPY(x) ADM_info(#x":%d\n",(int)spsinfo->x);
1206 #if 1
1207
1208 bool l=extractSPSInfo_lavcodec(data,len,spsinfo);
1209 if(l)
1210 {
1211 DPY(width);
1212 DPY(height);
1213 DPY(fps1000);
1214 DPY(hasStructInfo);
1215 DPY(hasPocInfo);
1216 DPY(CpbDpbToSkip);
1217 DPY(log2MaxFrameNum);
1218 DPY(log2MaxPocLsb);
1219 DPY(frameMbsOnlyFlag);
1220 DPY(darNum);
1221 DPY(darDen);
1222 }else
1223 {
1224 ADM_info("Failed\n.");
1225 }
1226 return l;
1227
1228 #else
1229 bool i=extractSPSInfo_internal(data,len,spsinfo);
1230 DPY(width);
1231 DPY(height);
1232 DPY(fps1000);
1233 DPY(hasStructInfo);
1234 DPY(CpbDpbToSkip);
1235 DPY(darNum);
1236 DPY(darDen);
1237 return i;
1238 #endif
1239 }
1240 /**
1241 \fn packNalu
1242 \brief convert mpeg type NALU into mp4 header type nalu
1243 */
packNalu(int idx,NALU_descriptor * nalus,uint32_t * len,uint8_t ** data)1244 static void packNalu(int idx,NALU_descriptor *nalus,uint32_t *len,uint8_t **data)
1245 {
1246 NALU_descriptor *n=nalus+idx;
1247 uint32_t size=n->size;
1248 uint8_t *p=new uint8_t[size+1];
1249 *data=p;
1250 p[0]=n->nalu;
1251 *len=1+ADM_unescapeH264(n->size, n->start,p+1);
1252 }
1253 /**
1254 \fn ADM_getH264SpsPpsFromExtraData
1255 \brief Returns a copy of PPS/SPS extracted from extrdata
1256 */
ADM_getH264SpsPpsFromExtraData(uint32_t extraLen,uint8_t * extra,uint32_t * spsLen,uint8_t ** spsData,uint32_t * ppsLen,uint8_t ** ppsData)1257 bool ADM_getH264SpsPpsFromExtraData(uint32_t extraLen,uint8_t *extra,
1258 uint32_t *spsLen,uint8_t **spsData,
1259 uint32_t *ppsLen,uint8_t **ppsData)
1260 {
1261
1262 if(extraLen<7) // not mov/mp4 formatted...
1263 {
1264 ADM_error("Wrong extra data for h264\n");
1265 return false;
1266 }
1267 //
1268 if(extra[0]==1) // MP4-type extradata
1269 {
1270 ADM_info("MP4 style PPS/SPS\n");
1271
1272 int nbSps=extra[5]&0x1f;
1273 if(nbSps!=1)
1274 {
1275 ADM_error("More or less than 1 sps\n");
1276 return false;
1277
1278 }
1279 uint8_t *c=extra+6;
1280 *spsLen= (c[0]<<8)+(c[1]);
1281 *spsData=c+2;
1282 c+=2+*spsLen;
1283 int nbPps=c[0]&0x1f;
1284 if(nbPps!=1)
1285 {
1286 ADM_error("More or less than 1 pps\n");
1287 return false;
1288 }
1289 c++;
1290 *ppsLen= (c[0]<<8)+(c[1]);
1291 *ppsData=c+2;
1292 // Duplicate
1293 uint8_t *y=new uint8_t [*spsLen];
1294 memcpy(y,*spsData,*spsLen);
1295 *spsData=y;
1296 y=new uint8_t [*ppsLen];
1297 memcpy(y,*ppsData,*ppsLen);
1298 *ppsData=y;
1299 ADM_info("Got extradata, ppslen=%d, spslen=%d\n",(int)(*ppsLen),(int)*spsLen);
1300 return true;
1301
1302 }else
1303 if(!extra[0] && !extra[1])
1304 if(extra[2]==1 || (!extra[2] && extra[3]==1)) // 00 00 01 type extradata
1305 {
1306 ADM_info("Startcoded PPS/SPS\n");
1307 #define NALU_COUNT 10
1308 NALU_descriptor nalus[NALU_COUNT];
1309 int nbNalus=ADM_splitNalu(extra, extraLen+extra, NALU_COUNT,nalus);
1310 //int ADM_findNalu(uint32_t nalu,uint32_t maxNalu,NALU_descriptor *desc);
1311 if(nbNalus<2)
1312 {
1313 ADM_error("Not enough nalus in extradata (%s)\n",nbNalus);
1314 return false;
1315 }
1316 int spsIndex=ADM_findNalu(NAL_SPS,nbNalus,nalus);
1317 int ppsIndex=ADM_findNalu(NAL_PPS,nbNalus,nalus);
1318 if(-1==spsIndex || -1 == ppsIndex)
1319 {
1320 ADM_error("Cant find sps/pps in nalus\n");
1321 return false;
1322 }
1323 packNalu(spsIndex,nalus,spsLen,spsData);
1324 packNalu(ppsIndex,nalus,ppsLen,ppsData);
1325 return true;
1326 }
1327 return false;
1328 }
1329 /**
1330 \fn ADM_splitNalu
1331 \brief split a nalu annexb size into a list of nalu descriptor
1332 */
ADM_splitNalu(uint8_t * start,uint8_t * end,uint32_t maxNalu,NALU_descriptor * desc)1333 int ADM_splitNalu(uint8_t *start, uint8_t *end, uint32_t maxNalu,NALU_descriptor *desc)
1334 {
1335 bool first=true;
1336 uint8_t *head=start;
1337 uint32_t offset;
1338 uint8_t startCode,oldStartCode=0xff;
1339 bool zeroBytePrefixed,oldZbp=false;
1340 const uint32_t startCodePrefixLen=4;
1341 int index=0;
1342
1343 while(true==ADM_findAnnexBStartCode(head,end,&startCode,&offset,&zeroBytePrefixed))
1344 {
1345 if(true==first)
1346 {
1347 head+=offset;
1348 first=false;
1349 oldStartCode=startCode;
1350 oldZbp=zeroBytePrefixed;
1351 continue;
1352 }
1353 if(index>=maxNalu)
1354 {
1355 ADM_warning("Number of NALUs exceeds max (%d), dropping the leftover.\n",maxNalu);
1356 return index;
1357 }
1358 desc[index].start=head;
1359 desc[index].size=offset-zeroBytePrefixed-startCodePrefixLen;
1360 desc[index].nalu=oldStartCode;
1361 desc[index].zerobyte=oldZbp;
1362 index++;
1363 head+=offset;
1364 oldStartCode=startCode;
1365 oldZbp=zeroBytePrefixed;
1366 }
1367 // leftover
1368 desc[index].start=head;
1369 desc[index].size=(uint32_t)(end-head);
1370 desc[index].nalu=oldStartCode;
1371 desc[index].zerobyte=oldZbp;
1372 index++;
1373 return index;
1374 }
1375 /**
1376 \fn ADM_findNalu
1377 \brief lookup for a specific NALU in the given buffer
1378 */
ADM_findNalu(uint32_t nalu,uint32_t maxNalu,NALU_descriptor * desc)1379 int ADM_findNalu(uint32_t nalu,uint32_t maxNalu,NALU_descriptor *desc)
1380 {
1381 for(int i=0;i<maxNalu;i++)
1382 {
1383 if((desc[i].nalu&0x1f) == (nalu&0x1f))
1384 return i;
1385 }
1386 return -1;
1387 }
writeBE32(uint8_t * p,uint32_t size)1388 static void writeBE32(uint8_t *p, uint32_t size)
1389 {
1390 p[0]=size>>24;
1391 p[1]=(size>>16)&0xff;
1392 p[2]=(size>>8)&0xff;
1393 p[3]=(size>>0)&0xff;
1394 }
1395 /**
1396 \fn ADM_convertFromAnnexBToMP4_internal
1397 \brief convert annexB startcode (00 00 00 0 xx) to NALU
1398 */
ADM_convertFromAnnexBToMP4(uint8_t * inData,uint32_t inSize,uint8_t * outData,uint32_t outMaxSize)1399 int ADM_convertFromAnnexBToMP4(uint8_t *inData, uint32_t inSize,
1400 uint8_t *outData,uint32_t outMaxSize)
1401 {
1402 uint8_t *tgt=outData;
1403 NALU_descriptor desc[MAX_NALU_PER_CHUNK+1];
1404 int nbNalu=ADM_splitNalu(inData,inData+inSize,MAX_NALU_PER_CHUNK,desc);
1405 const int nalHeaderSize=4;
1406 int outputSize=0;
1407
1408
1409 for(int i=0;i<nbNalu;i++)
1410 {
1411 NALU_descriptor *d=desc+i;
1412 aprintf("%d/%d : Nalu :0x%x size=%d\n",i,nbNalu,d->nalu,d->size);
1413 switch(d->nalu&0x1f)
1414 {
1415 case NAL_FILLER: break;
1416 case NAL_AU_DELIMITER: break;
1417 default:
1418 writeBE32(tgt,1+d->size);
1419 tgt[nalHeaderSize]=d->nalu;
1420 memcpy(tgt+1+nalHeaderSize,d->start,d->size);
1421 tgt+=d->size+1+nalHeaderSize;
1422 break;
1423 }
1424 outputSize=tgt-outData;
1425 ADM_assert(outputSize<outMaxSize);
1426 }
1427 return outputSize;
1428 }
1429 //EOF
1430