History

avformat/hevc: add a function to write a lhvC box

James Almer committed 2 years ago

Commit cbfbacf1 parent cee43e52 files · +145 −35Browse files

Showing the changes to libavformat (2 of 2 files). Show all

Unified · Split

2 files
  1. libavformat/hevc.c +128 −35
  2. libavformat/hevc.h +17 −0
libavformat/hevc.c+128−35
@@ -43,12 +43,16 @@ enum { · 42 unmodified lines
43 43
44#define FLAG_ARRAY_COMPLETENESS (1 << 0)44#define FLAG_ARRAY_COMPLETENESS (1 << 0)
45#define FLAG_IS_NALFF (1 << 1)45#define FLAG_IS_NALFF (1 << 1)
46#define FLAG_IS_LHVC (1 << 2)
46 47
47typedef struct HVCCNALUnit {48typedef struct HVCCNALUnit {
48 uint8_t nuh_layer_id;49 uint8_t nuh_layer_id;
49 uint8_t parameter_set_id;50 uint8_t parameter_set_id;
50 uint16_t nalUnitLength;51 uint16_t nalUnitLength;
51 const uint8_t *nalUnit;52 const uint8_t *nalUnit;
53
54 // VPS
55 uint8_t vps_max_sub_layers_minus1;
52} HVCCNALUnit;56} HVCCNALUnit;
53 57
54typedef struct HVCCNALUnitArray {58typedef struct HVCCNALUnitArray {
@@ -383,8 +387,6 @@ static void skip_sub_layer_ordering_info(GetBitContext *gb) · 328 unmodified lines
383static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal,387static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal,
384 HEVCDecoderConfigurationRecord *hvcc)388 HEVCDecoderConfigurationRecord *hvcc)
385{389{
386 unsigned int vps_max_sub_layers_minus1;
387
388 nal->parameter_set_id = get_bits(gb, 4);390 nal->parameter_set_id = get_bits(gb, 4);
389 /*391 /*
390 * vps_reserved_three_2bits u(2)392 * vps_reserved_three_2bits u(2)
@@ -392,7 +394,7 @@ static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal, · 1 unmodified line
392 */394 */
393 skip_bits(gb, 8);395 skip_bits(gb, 8);
394 396
395 vps_max_sub_layers_minus1 = get_bits(gb, 3);397 nal->vps_max_sub_layers_minus1 = get_bits(gb, 3);
396 398
397 /*399 /*
398 * numTemporalLayers greater than 1 indicates that the stream to which this400 * numTemporalLayers greater than 1 indicates that the stream to which this
@@ -403,7 +405,7 @@ static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal, · 4 unmodified lines
403 * that it is unknown whether the stream is temporally scalable.405 * that it is unknown whether the stream is temporally scalable.
404 */406 */
405 hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers,407 hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers,
406 vps_max_sub_layers_minus1 + 1);408 nal->vps_max_sub_layers_minus1 + 1);
407 409
408 /*410 /*
409 * vps_temporal_id_nesting_flag u(1)411 * vps_temporal_id_nesting_flag u(1)
@@ -411,7 +413,7 @@ static int hvcc_parse_vps(GetBitContext *gb, HVCCNALUnit *nal, · 1 unmodified line
411 */413 */
412 skip_bits(gb, 17);414 skip_bits(gb, 17);
413 415
414 hvcc_parse_ptl(gb, hvcc, vps_max_sub_layers_minus1);416 hvcc_parse_ptl(gb, hvcc, nal->vps_max_sub_layers_minus1);
415 417
416 /* nothing useful for hvcC past this point */418 /* nothing useful for hvcC past this point */
417 return 0;419 return 0;
@@ -508,10 +510,33 @@ static int hvcc_parse_sps(GetBitContext *gb, HVCCNALUnit *nal, · 90 unmodified lines
508{510{
509 unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4;511 unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4;
510 unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS];512 unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS];
513 unsigned int sps_ext_or_max_sub_layers_minus1, multi_layer_ext_sps_flag;
514
515 unsigned int sps_video_parameter_set_id = get_bits(gb, 4);
511 516
512 skip_bits(gb, 4); // sps_video_parameter_set_id517 if (nal->nuh_layer_id == 0) {
518 sps_ext_or_max_sub_layers_minus1 = 0;
519 sps_max_sub_layers_minus1 = get_bits(gb, 3);
520 } else {
521 sps_ext_or_max_sub_layers_minus1 = get_bits(gb, 3);
522 if (sps_ext_or_max_sub_layers_minus1 == 7) {
523 const HVCCNALUnitArray *array = &hvcc->arrays[VPS_INDEX];
524 const HVCCNALUnit *vps = NULL;
525
526 for (i = 0; i < array->numNalus; i++)
527 if (sps_video_parameter_set_id == array->nal[i].parameter_set_id) {
528 vps = &array->nal[i];
529 break;
530 }
531 if (!vps)
532 return AVERROR_INVALIDDATA;
513 533
514 sps_max_sub_layers_minus1 = get_bits (gb, 3);534 sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1;
535 } else
536 sps_max_sub_layers_minus1 = sps_ext_or_max_sub_layers_minus1;
537 }
538 multi_layer_ext_sps_flag = nal->nuh_layer_id &&
539 sps_ext_or_max_sub_layers_minus1 == 7;
515 540
516 /*541 /*
517 * numTemporalLayers greater than 1 indicates that the stream to which this542 * numTemporalLayers greater than 1 indicates that the stream to which this
@@ -524,12 +549,17 @@ static int hvcc_parse_sps(GetBitContext *gb, HVCCNALUnit *nal, · 6 unmodified lines
524 hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers,549 hvcc->numTemporalLayers = FFMAX(hvcc->numTemporalLayers,
525 sps_max_sub_layers_minus1 + 1);550 sps_max_sub_layers_minus1 + 1);
526 551
527 hvcc->temporalIdNested = get_bits1(gb);552 if (!multi_layer_ext_sps_flag) {
528 553 hvcc->temporalIdNested = get_bits1(gb);
529 hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1);554 hvcc_parse_ptl(gb, hvcc, sps_max_sub_layers_minus1);
555 }
530 556
531 nal->parameter_set_id = get_ue_golomb_long(gb);557 nal->parameter_set_id = get_ue_golomb_long(gb);
532 558
559 if (multi_layer_ext_sps_flag) {
560 if (get_bits1(gb)) // update_rep_format_flag
561 skip_bits(gb, 8); // sps_rep_format_idx
562 } else {
533 hvcc->chromaFormat = get_ue_golomb_long(gb);563 hvcc->chromaFormat = get_ue_golomb_long(gb);
534 564
535 if (hvcc->chromaFormat == 3)565 if (hvcc->chromaFormat == 3)
@@ -547,12 +577,15 @@ static int hvcc_parse_sps(GetBitContext *gb, HVCCNALUnit *nal, · 11 unmodified lines
547 577
548 hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb);578 hvcc->bitDepthLumaMinus8 = get_ue_golomb_long(gb);
549 hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb);579 hvcc->bitDepthChromaMinus8 = get_ue_golomb_long(gb);
580 }
550 log2_max_pic_order_cnt_lsb_minus4 = get_ue_golomb_long(gb);581 log2_max_pic_order_cnt_lsb_minus4 = get_ue_golomb_long(gb);
551 582
583 if (!multi_layer_ext_sps_flag) {
552 /* sps_sub_layer_ordering_info_present_flag */584 /* sps_sub_layer_ordering_info_present_flag */
553 i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1;585 i = get_bits1(gb) ? 0 : sps_max_sub_layers_minus1;
554 for (; i <= sps_max_sub_layers_minus1; i++)586 for (; i <= sps_max_sub_layers_minus1; i++)
555 skip_sub_layer_ordering_info(gb);587 skip_sub_layer_ordering_info(gb);
588 }
556 589
557 get_ue_golomb_long(gb); // log2_min_luma_coding_block_size_minus3590 get_ue_golomb_long(gb); // log2_min_luma_coding_block_size_minus3
558 get_ue_golomb_long(gb); // log2_diff_max_min_luma_coding_block_size591 get_ue_golomb_long(gb); // log2_diff_max_min_luma_coding_block_size
@@ -561,9 +594,15 @@ static int hvcc_parse_sps(GetBitContext *gb, HVCCNALUnit *nal, · 2 unmodified lines
561 get_ue_golomb_long(gb); // max_transform_hierarchy_depth_inter594 get_ue_golomb_long(gb); // max_transform_hierarchy_depth_inter
562 get_ue_golomb_long(gb); // max_transform_hierarchy_depth_intra595 get_ue_golomb_long(gb); // max_transform_hierarchy_depth_intra
563 596
564 if (get_bits1(gb) && // scaling_list_enabled_flag597 if (get_bits1(gb)) { // scaling_list_enabled_flag
565 get_bits1(gb)) // sps_scaling_list_data_present_flag598 int sps_infer_scaling_list_flag = 0;
566 skip_scaling_list_data(gb);599 if (multi_layer_ext_sps_flag)
600 sps_infer_scaling_list_flag = get_bits1(gb);
601 if (sps_infer_scaling_list_flag)
602 skip_bits(gb, 6); // sps_scaling_list_ref_layer_id
603 else if (get_bits1(gb)) // sps_scaling_list_data_present_flag
604 skip_scaling_list_data(gb);
605 }
567 606
568 skip_bits1(gb); // amp_enabled_flag607 skip_bits1(gb); // amp_enabled_flag
569 skip_bits1(gb); // sample_adaptive_offset_enabled_flag608 skip_bits1(gb); // sample_adaptive_offset_enabled_flag
@@ -703,6 +742,7 @@ static int hvcc_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size, · 133 unmodified lines
703{742{
704 int ret = 0;743 int ret = 0;
705 int is_nalff = !!(flags & FLAG_IS_NALFF);744 int is_nalff = !!(flags & FLAG_IS_NALFF);
745 int is_lhvc = !!(flags & FLAG_IS_LHVC);
706 int ps_array_completeness = !!(flags & FLAG_ARRAY_COMPLETENESS);746 int ps_array_completeness = !!(flags & FLAG_ARRAY_COMPLETENESS);
707 HVCCNALUnitArray *const array = &hvcc->arrays[array_idx];747 HVCCNALUnitArray *const array = &hvcc->arrays[array_idx];
708 HVCCNALUnit *nal;748 HVCCNALUnit *nal;
@@ -722,7 +762,7 @@ static int hvcc_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size, · 13 unmodified lines
722 goto end;762 goto end;
723 763
724 nal_unit_parse_header(&gbc, &nal_type, &nuh_layer_id);764 nal_unit_parse_header(&gbc, &nal_type, &nuh_layer_id);
725 if (nuh_layer_id > 0)765 if (!is_lhvc && nuh_layer_id > 0)
726 goto end;766 goto end;
727 767
728 /*768 /*
@@ -798,9 +838,12 @@ static void hvcc_close(HEVCDecoderConfigurationRecord *hvcc) · 69 unmodified lines
798 }838 }
799}839}
800 840
801static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc)841static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc,
842 int flags)
802{843{
803 uint16_t vps_count, sps_count, pps_count;844 uint16_t numNalus[NB_ARRAYS] = { 0 };
845 int is_lhvc = !!(flags & FLAG_IS_LHVC);
846 int numOfArrays = 0;
804 847
805 /*848 /*
806 * We only support writing HEVCDecoderConfigurationRecord version 1.849 * We only support writing HEVCDecoderConfigurationRecord version 1.
@@ -826,10 +869,32 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 19 unmodified lines
826 * let's always set them to values meaning 'unspecified'.869 * let's always set them to values meaning 'unspecified'.
827 */870 */
828 hvcc->avgFrameRate = 0;871 hvcc->avgFrameRate = 0;
829 hvcc->constantFrameRate = 0;872 /*
873 * lhvC doesn't store this field. It instead reserves the bits, setting them
874 * to '11'b.
875 */
876 hvcc->constantFrameRate = is_lhvc * 0x3;
877
878 /*
879 * Skip all NALUs with nuh_layer_id == 0 if writing lhvC. We do it here and
880 * not before parsing them as some parameter sets with nuh_layer_id > 0
881 * may reference base layer parameters sets.
882 */
883 for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) {
884 const HVCCNALUnitArray *const array = &hvcc->arrays[i];
885
886 if (array->numNalus == 0)
887 continue;
830 888
889 for (unsigned j = 0; j < array->numNalus; j++)
890 numNalus[i] += !is_lhvc || (array->nal[j].nuh_layer_id != 0);
891 numOfArrays += (numNalus[i] > 0);
892 }
893
894 av_log(NULL, AV_LOG_TRACE, "%s\n", is_lhvc ? "lhvC" : "hvcC");
831 av_log(NULL, AV_LOG_TRACE, "configurationVersion: %"PRIu8"\n",895 av_log(NULL, AV_LOG_TRACE, "configurationVersion: %"PRIu8"\n",
832 hvcc->configurationVersion);896 hvcc->configurationVersion);
897 if (!is_lhvc) {
833 av_log(NULL, AV_LOG_TRACE, "general_profile_space: %"PRIu8"\n",898 av_log(NULL, AV_LOG_TRACE, "general_profile_space: %"PRIu8"\n",
834 hvcc->general_profile_space);899 hvcc->general_profile_space);
835 av_log(NULL, AV_LOG_TRACE, "general_tier_flag: %"PRIu8"\n",900 av_log(NULL, AV_LOG_TRACE, "general_tier_flag: %"PRIu8"\n",
@@ -842,10 +907,12 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 6 unmodified lines
842 hvcc->general_constraint_indicator_flags);907 hvcc->general_constraint_indicator_flags);
843 av_log(NULL, AV_LOG_TRACE, "general_level_idc: %"PRIu8"\n",908 av_log(NULL, AV_LOG_TRACE, "general_level_idc: %"PRIu8"\n",
844 hvcc->general_level_idc);909 hvcc->general_level_idc);
910 }
845 av_log(NULL, AV_LOG_TRACE, "min_spatial_segmentation_idc: %"PRIu16"\n",911 av_log(NULL, AV_LOG_TRACE, "min_spatial_segmentation_idc: %"PRIu16"\n",
846 hvcc->min_spatial_segmentation_idc);912 hvcc->min_spatial_segmentation_idc);
847 av_log(NULL, AV_LOG_TRACE, "parallelismType: %"PRIu8"\n",913 av_log(NULL, AV_LOG_TRACE, "parallelismType: %"PRIu8"\n",
848 hvcc->parallelismType);914 hvcc->parallelismType);
915 if (!is_lhvc) {
849 av_log(NULL, AV_LOG_TRACE, "chromaFormat: %"PRIu8"\n",916 av_log(NULL, AV_LOG_TRACE, "chromaFormat: %"PRIu8"\n",
850 hvcc->chromaFormat);917 hvcc->chromaFormat);
851 av_log(NULL, AV_LOG_TRACE, "bitDepthLumaMinus8: %"PRIu8"\n",918 av_log(NULL, AV_LOG_TRACE, "bitDepthLumaMinus8: %"PRIu8"\n",
@@ -856,6 +923,7 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 4 unmodified lines
856 hvcc->avgFrameRate);923 hvcc->avgFrameRate);
857 av_log(NULL, AV_LOG_TRACE, "constantFrameRate: %"PRIu8"\n",924 av_log(NULL, AV_LOG_TRACE, "constantFrameRate: %"PRIu8"\n",
858 hvcc->constantFrameRate);925 hvcc->constantFrameRate);
926 }
859 av_log(NULL, AV_LOG_TRACE, "numTemporalLayers: %"PRIu8"\n",927 av_log(NULL, AV_LOG_TRACE, "numTemporalLayers: %"PRIu8"\n",
860 hvcc->numTemporalLayers);928 hvcc->numTemporalLayers);
861 av_log(NULL, AV_LOG_TRACE, "temporalIdNested: %"PRIu8"\n",929 av_log(NULL, AV_LOG_TRACE, "temporalIdNested: %"PRIu8"\n",
@@ -863,11 +931,11 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 1 unmodified line
863 av_log(NULL, AV_LOG_TRACE, "lengthSizeMinusOne: %"PRIu8"\n",931 av_log(NULL, AV_LOG_TRACE, "lengthSizeMinusOne: %"PRIu8"\n",
864 hvcc->lengthSizeMinusOne);932 hvcc->lengthSizeMinusOne);
865 av_log(NULL, AV_LOG_TRACE, "numOfArrays: %"PRIu8"\n",933 av_log(NULL, AV_LOG_TRACE, "numOfArrays: %"PRIu8"\n",
866 hvcc->numOfArrays);934 numOfArrays);
867 for (unsigned i = 0, j = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) {935 for (unsigned i = 0, j = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) {
868 const HVCCNALUnitArray *const array = &hvcc->arrays[i];936 const HVCCNALUnitArray *const array = &hvcc->arrays[i];
869 937
870 if (array->numNalus == 0)938 if (numNalus[i] == 0)
871 continue;939 continue;
872 940
873 av_log(NULL, AV_LOG_TRACE, "array_completeness[%u]: %"PRIu8"\n",941 av_log(NULL, AV_LOG_TRACE, "array_completeness[%u]: %"PRIu8"\n",
@@ -875,28 +943,31 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 1 unmodified line
875 av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%u]: %"PRIu8"\n",943 av_log(NULL, AV_LOG_TRACE, "NAL_unit_type[%u]: %"PRIu8"\n",
876 j, array->NAL_unit_type);944 j, array->NAL_unit_type);
877 av_log(NULL, AV_LOG_TRACE, "numNalus[%u]: %"PRIu16"\n",945 av_log(NULL, AV_LOG_TRACE, "numNalus[%u]: %"PRIu16"\n",
878 j, array->numNalus);946 j, numNalus[i]);
879 for (unsigned k = 0; k < array->numNalus; k++)947 for (unsigned k = 0; k < array->numNalus; k++) {
948 if (is_lhvc && array->nal[k].nuh_layer_id == 0)
949 continue;
950
880 av_log(NULL, AV_LOG_TRACE,951 av_log(NULL, AV_LOG_TRACE,
881 "nalUnitLength[%u][%u]: %"PRIu16"\n",952 "nalUnitLength[%u][%u]: %"PRIu16"\n",
882 j, k, array->nal[k].nalUnitLength);953 j, k, array->nal[k].nalUnitLength);
954 }
883 j++;955 j++;
884 }956 }
885 957
886 /*958 /*
887 * We need at least one of each: VPS, SPS and PPS.959 * We need at least one of each: VPS, SPS and PPS.
888 */960 */
889 vps_count = hvcc->arrays[VPS_INDEX].numNalus;961 if ((!numNalus[VPS_INDEX] || numNalus[VPS_INDEX] > HEVC_MAX_VPS_COUNT) && !is_lhvc)
890 sps_count = hvcc->arrays[SPS_INDEX].numNalus;962 return AVERROR_INVALIDDATA;
891 pps_count = hvcc->arrays[PPS_INDEX].numNalus;963 if (!numNalus[SPS_INDEX] || numNalus[SPS_INDEX] > HEVC_MAX_SPS_COUNT ||
892 if (!vps_count || vps_count > HEVC_MAX_VPS_COUNT ||964 !numNalus[PPS_INDEX] || numNalus[PPS_INDEX] > HEVC_MAX_PPS_COUNT)
893 !sps_count || sps_count > HEVC_MAX_SPS_COUNT ||
894 !pps_count || pps_count > HEVC_MAX_PPS_COUNT)
895 return AVERROR_INVALIDDATA;965 return AVERROR_INVALIDDATA;
896 966
897 /* unsigned int(8) configurationVersion = 1; */967 /* unsigned int(8) configurationVersion = 1; */
898 avio_w8(pb, hvcc->configurationVersion);968 avio_w8(pb, hvcc->configurationVersion);
899 969
970 if (!is_lhvc) {
900 /*971 /*
901 * unsigned int(2) general_profile_space;972 * unsigned int(2) general_profile_space;
902 * unsigned int(1) general_tier_flag;973 * unsigned int(1) general_tier_flag;
@@ -915,6 +986,7 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 12 unmodified lines
915 986
916 /* unsigned int(8) general_level_idc; */987 /* unsigned int(8) general_level_idc; */
917 avio_w8(pb, hvcc->general_level_idc);988 avio_w8(pb, hvcc->general_level_idc);
989 }
918 990
919 /*991 /*
920 * bit(4) reserved = '1111'b;992 * bit(4) reserved = '1111'b;
@@ -928,6 +1000,7 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 7 unmodified lines
928 */1000 */
929 avio_w8(pb, hvcc->parallelismType | 0xfc);1001 avio_w8(pb, hvcc->parallelismType | 0xfc);
930 1002
1003 if (!is_lhvc) {
931 /*1004 /*
932 * bit(6) reserved = '111111'b;1005 * bit(6) reserved = '111111'b;
933 * unsigned int(2) chromaFormat;1006 * unsigned int(2) chromaFormat;
@@ -948,9 +1021,13 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 14 unmodified lines
948 1021
949 /* bit(16) avgFrameRate; */1022 /* bit(16) avgFrameRate; */
950 avio_wb16(pb, hvcc->avgFrameRate);1023 avio_wb16(pb, hvcc->avgFrameRate);
1024 }
951 1025
952 /*1026 /*
1027 * if (!is_lhvc)
953 * bit(2) constantFrameRate;1028 * bit(2) constantFrameRate;
1029 * else
1030 * bit(2) reserved = '11'b;
954 * bit(3) numTemporalLayers;1031 * bit(3) numTemporalLayers;
955 * bit(1) temporalIdNested;1032 * bit(1) temporalIdNested;
956 * unsigned int(2) lengthSizeMinusOne;1033 * unsigned int(2) lengthSizeMinusOne;
@@ -961,12 +1038,12 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 4 unmodified lines
961 hvcc->lengthSizeMinusOne);1038 hvcc->lengthSizeMinusOne);
962 1039
963 /* unsigned int(8) numOfArrays; */1040 /* unsigned int(8) numOfArrays; */
964 avio_w8(pb, hvcc->numOfArrays);1041 avio_w8(pb, numOfArrays);
965 1042
966 for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) {1043 for (unsigned i = 0; i < FF_ARRAY_ELEMS(hvcc->arrays); i++) {
967 const HVCCNALUnitArray *const array = &hvcc->arrays[i];1044 const HVCCNALUnitArray *const array = &hvcc->arrays[i];
968 1045
969 if (!array->numNalus)1046 if (!numNalus[i])
970 continue;1047 continue;
971 /*1048 /*
972 * bit(1) array_completeness;1049 * bit(1) array_completeness;
@@ -977,11 +1054,14 @@ static int hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc) · 4 unmodified lines
977 array->NAL_unit_type & 0x3f);1054 array->NAL_unit_type & 0x3f);
978 1055
979 /* unsigned int(16) numNalus; */1056 /* unsigned int(16) numNalus; */
980 avio_wb16(pb, array->numNalus);1057 avio_wb16(pb, numNalus[i]);
981 1058
982 for (unsigned j = 0; j < array->numNalus; j++) {1059 for (unsigned j = 0; j < array->numNalus; j++) {
983 HVCCNALUnit *nal = &array->nal[j];1060 HVCCNALUnit *nal = &array->nal[j];
984 1061
1062 if (is_lhvc && nal->nuh_layer_id == 0)
1063 continue;
1064
985 /* unsigned int(16) nalUnitLength; */1065 /* unsigned int(16) nalUnitLength; */
986 avio_wb16(pb, nal->nalUnitLength);1066 avio_wb16(pb, nal->nalUnitLength);
987 1067
@@ -1082,12 +1162,11 @@ static int hvcc_parse_nal_unit(const uint8_t *buf, uint32_t len, int type, · 94 unmodified lines
1082 return 0;1162 return 0;
1083}1163}
1084 1164
1085int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,1165static int write_configuration_record(AVIOContext *pb, const uint8_t *data,
1086 int size, int ps_array_completeness)1166 int size, int flags)
1087{1167{
1088 HEVCDecoderConfigurationRecord hvcc;1168 HEVCDecoderConfigurationRecord hvcc;
1089 uint8_t *buf, *end, *start = NULL;1169 uint8_t *buf, *end, *start = NULL;
1090 int flags = !!ps_array_completeness * FLAG_ARRAY_COMPLETENESS;
1091 int ret;1170 int ret;
1092 1171
1093 if (size < 6) {1172 if (size < 6) {
@@ -1154,7 +1233,7 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, · 60 unmodified lines
1154 }1233 }
1155 }1234 }
1156 1235
1157 ret = hvcc_write(pb, &hvcc);1236 ret = hvcc_write(pb, &hvcc, flags);
1158 goto end;1237 goto end;
1159 } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) {1238 } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) {
1160 /* Not a valid Annex B start code prefix */1239 /* Not a valid Annex B start code prefix */
@@ -1183,10 +1262,24 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data, · 22 unmodified lines
1183 buf += len;1262 buf += len;
1184 }1263 }
1185 1264
1186 ret = hvcc_write(pb, &hvcc);1265 ret = hvcc_write(pb, &hvcc, flags);
1187 1266
1188end:1267end:
1189 hvcc_close(&hvcc);1268 hvcc_close(&hvcc);
1190 av_free(start);1269 av_free(start);
1191 return ret;1270 return ret;
1192}1271}
1272
1273int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
1274 int size, int ps_array_completeness)
1275{
1276 return write_configuration_record(pb, data, size,
1277 !!ps_array_completeness * FLAG_ARRAY_COMPLETENESS);
1278}
1279
1280int ff_isom_write_lhvc(AVIOContext *pb, const uint8_t *data,
1281 int size, int ps_array_completeness)
1282{
1283 return write_configuration_record(pb, data, size,
1284 (!!ps_array_completeness * FLAG_ARRAY_COMPLETENESS) | FLAG_IS_LHVC);
1285}
libavformat/hevc.h+17−0
@@ -97,4 +97,21 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, · 96 unmodified lines
97int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,97int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
98 int size, int ps_array_completeness);98 int size, int ps_array_completeness);
99 99
100/**
101 * Writes L-HEVC extradata (parameter sets with nuh_layer_id > 0, as a
102 * LHEVCDecoderConfigurationRecord) to the provided AVIOContext.
103 *
104 * If the extradata is Annex B format, it gets converted to lhvC format before
105 * writing. Otherwise, hvcC formated extradata is expected, not lhvC.
106 *
107 * @param pb address of the AVIOContext where the lhvC shall be written
108 * @param data address of the buffer holding the data needed to write the lhvC
109 * @param size size (in bytes) of the data buffer
110 * @param ps_array_completeness whether all parameter sets are in the lhvC (1)
111 * or there may be additional parameter sets in the bitstream (0)
112 * @return >=0 in case of success, a negative value corresponding to an AVERROR
113 * code in case of failure
114 */
115int ff_isom_write_lhvc(AVIOContext *pb, const uint8_t *data,
116 int size, int ps_array_completeness);
100#endif /* AVFORMAT_HEVC_H */117#endif /* AVFORMAT_HEVC_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t