diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | decoder.cpp | 863 | ||||
-rw-r--r-- | decoder.h | 78 | ||||
-rw-r--r-- | markad-standalone.cpp | 36 | ||||
-rw-r--r-- | recv.cpp | 86 | ||||
-rw-r--r-- | recv.h | 5 | ||||
-rw-r--r-- | streaminfo.cpp | 827 | ||||
-rw-r--r-- | streaminfo.h | 98 | ||||
-rw-r--r-- | video.cpp | 141 | ||||
-rw-r--r-- | video.h | 22 |
10 files changed, 1137 insertions, 1037 deletions
@@ -11,11 +11,6 @@ # PLUGIN = markad -### ffmpeg usage #### -# -# Set this to 0, if you don't want to use ffmpeg -AVCODEC = 0 - ### The version number of this plugin (taken from the main source file): VERSION = $(shell grep 'static const char \*VERSION *=' version.h | awk '{ print $$6 }' | sed -e 's/[";]//g') @@ -55,17 +50,14 @@ INCLUDES += -I$(VDRDIR)/include DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -ifeq ($(AVCODEC),1) -DEFINES += -DHAVE_AVCODEC INCLUDES += $(shell $(PKG-CONFIG) --cflags $(PKG-INCLUDES)) -LIBS += $(shell $(PKG-CONFIG) --libs $(PKG-LIBS)) -endif +LIBS-CMD += $(shell $(PKG-CONFIG) --libs $(PKG-LIBS)) ### The object files (add further files here): -OBJS-CMD = markad-standalone.o -OBJS-COMMON = demux.o video.o audio.o decoder.o common.o tools.o vdr2pkt.o ts2pkt.o pes2es.o -OBJS = $(PLUGIN).o recv.o status.o $(OBJS-COMMON) +OBJS-CMD = markad-standalone.o decoder.o +OBJS-COMMON = common.o video.o audio.o demux.o tools.o vdr2pkt.o ts2pkt.o pes2es.o +OBJS = $(PLUGIN).o recv.o status.o streaminfo.o $(OBJS-COMMON) ### The main target: @@ -118,7 +110,7 @@ libvdr-$(PLUGIN).so: $(OBJS) @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) $(PLUGIN): $(OBJS-COMMON) $(OBJS-CMD) - $(CXX) $(CXXFLAGS) $(OBJS-COMMON) $(OBJS-CMD) $(LIBS) -o $@ + $(CXX) $(CXXFLAGS) $(OBJS-COMMON) $(OBJS-CMD) $(LIBS-CMD) -o $@ dist: clean @-rm -rf $(TMPDIR)/$(ARCHIVE) diff --git a/decoder.cpp b/decoder.cpp index ef34fb8..27c4bf2 100644 --- a/decoder.cpp +++ b/decoder.cpp @@ -8,720 +8,9 @@ #include "decoder.h" -void cMarkAdDecoder::FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen) -{ - if ((!maContext) || (!espkt)) return; - -#pragma pack(1) - struct AC3HDR - { -unsigned Sync1: - 8; -unsigned Sync2: - 8; -unsigned CrcH: - 8; -unsigned CrcL: - 8; -unsigned FrameSizeIndex: - 6; -unsigned SampleRateIndex: - 2; -unsigned BsMod: - 3; -unsigned BsID: - 5; -unsigned LFE_Mix_VarField: - 5; -unsigned AcMod: - 3; - }; -#pragma pack() - - struct AC3HDR *ac3hdr = (struct AC3HDR *) espkt; - - if ((ac3hdr->Sync1==0x0b) && (ac3hdr->Sync2==0x77)) - { - // some extra checks - if (ac3hdr->SampleRateIndex==3) return; // reserved - if (ac3hdr->FrameSizeIndex>=38) return; // reserved - - maContext->Audio.Info.Channels=0; - int lfe_bitmask = 0x0; - - switch (ac3hdr->AcMod) - { - case 0: - maContext->Audio.Info.Channels=2; - lfe_bitmask=0x10; - break; - case 1: - maContext->Audio.Info.Channels=1; - lfe_bitmask=0x10; - break; - case 2: - maContext->Audio.Info.Channels=2; - lfe_bitmask=0x4; - break; - case 3: - maContext->Audio.Info.Channels=3; - lfe_bitmask=0x4; - break; - case 4: - maContext->Audio.Info.Channels=3; - lfe_bitmask=0x4; - break; - case 5: - maContext->Audio.Info.Channels=4; - lfe_bitmask=0x1; - break; - case 6: - maContext->Audio.Info.Channels=4; - lfe_bitmask=0x4; - break; - case 7: - maContext->Audio.Info.Channels=5; - lfe_bitmask=0x1; - break; - } - - if ((ac3hdr->LFE_Mix_VarField & lfe_bitmask)==lfe_bitmask) - maContext->Audio.Info.Channels++; - } - -} - -void cMarkAdDecoder::FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len) -{ - if ((!maContext) || (!pkt) || (!len)) return; - if (!maContext->General.VPid.Type) return; - - if (maContext->General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) - { - FindH264VideoInfos(maContext, pkt, len); - } - else - { - FindH262VideoInfos(maContext, pkt, len); - } -} - -void cMarkAdDecoder::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) -{ - if ((!maContext) || (!pkt) || (!len)) return; - - maContext->Video.Info.Pict_Type=0; - - if ((pkt[3] & 0x1F)==NAL_AUD) - { - switch (pkt[4] >> 5) - { - case 0: - case 3: - case 5: // I_FRAME - maContext->Video.Info.Pict_Type=MA_I_TYPE; - break; - case 1: - case 4: - case 6: // P_FRAME; - maContext->Video.Info.Pict_Type=MA_P_TYPE; - break; - case 2: - case 7: // B_FRAME; - maContext->Video.Info.Pict_Type=MA_B_TYPE; - break; - default: // NO_PICTURE; - maContext->Video.Info.Pict_Type=0; - break; - } - } - - if ((pkt[3] & 0x1F)==NAL_SPS) - { - uint8_t nal_data[len]; - const uint8_t *end = pkt + len; - int nal_len = nalUnescape(nal_data, pkt + 4, int(end - pkt - 4)); - - int profile_idc, level_idc, constraint_set3_flag, pic_order_cnt_type, i, j; - cBitStream bs(nal_data, nal_len); - - uint32_t width=0; - uint32_t height=0; - uint32_t aspect_ratio_idc=0; - uint32_t video_format=0; - double frame_rate=0; - double bit_rate=0; - bool cpb_dpb_delays_present_flag=false; - bool pic_struct_present_flag=false; - bool frame_mbs_only_flag=false; - bool mb_adaptive_frame_field_flag=false; - uint32_t time_offset_length=0; - - profile_idc = bs.getU8(); // profile_idc - bs.skipBit(); // constraint_set0_flag - bs.skipBit(); // constraint_set1_flag - bs.skipBit(); // constraint_set2_flag - constraint_set3_flag = bs.getBit(); // constraint_set3_flag - bs.skipBits(4); // reserved_zero_4bits - level_idc = bs.getU8(); // level_idc - bs.skipUeGolomb(); // seq_parameter_set_id - - switch (profile_idc) - { - case 66: // baseline profile - case 77: // main profile - case 88: // extended profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 64000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 128000 : 192000; - break; - case 12: // level 1.2 - bit_rate = 384000; - break; - case 13: // level 1.3 - bit_rate = 768000; - break; - case 20: // level 2.0 - bit_rate = 2000000; - break; - case 21: // level 2.1 - bit_rate = 4000000; - break; - case 22: // level 2.2 - bit_rate = 4000000; - break; - case 30: // level 3.0 - bit_rate = 10000000; - break; - case 31: // level 3.1 - bit_rate = 14000000; - break; - case 32: // level 3.2 - bit_rate = 20000000; - break; - case 40: // level 4.0 - bit_rate = 20000000; - break; - case 41: // level 4.1 - bit_rate = 50000000; - break; - case 42: // level 4.2 - bit_rate = 50000000; - break; - case 50: // level 5.0 - bit_rate = 135000000; - break; - case 51: // level 5.1 - bit_rate = 240000000; - break; - default: - break; - } - break; - case 100: // high profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 80000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 160000 : 240000; - break; - case 12: // level 1.2 - bit_rate = 480000; - break; - case 13: // level 1.3 - bit_rate = 960000; - break; - case 20: // level 2.0 - bit_rate = 2500000; - break; - case 21: // level 2.1 - bit_rate = 5000000; - break; - case 22: // level 2.2 - bit_rate = 5000000; - break; - case 30: // level 3.0 - bit_rate = 12500000; - break; - case 31: // level 3.1 - bit_rate = 17500000; - break; - case 32: // level 3.2 - bit_rate = 25000000; - break; - case 40: // level 4.0 - bit_rate = 25000000; - break; - case 41: // level 4.1 - bit_rate = 62500000; - break; - case 42: // level 4.2 - bit_rate = 62500000; - break; - case 50: // level 5.0 - bit_rate = 168750000; - break; - case 51: // level 5.1 - bit_rate = 300000000; - break; - default: - break; - } - break; - case 110: // high 10 profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 192000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 384000 : 576000; - break; - case 12: // level 1.2 - bit_rate = 115200; - break; - case 13: // level 1.3 - bit_rate = 2304000; - break; - case 20: // level 2.0 - bit_rate = 6000000; - break; - case 21: // level 2.1 - bit_rate = 12000000; - break; - case 22: // level 2.2 - bit_rate = 12000000; - break; - case 30: // level 3.0 - bit_rate = 30000000; - break; - case 31: // level 3.1 - bit_rate = 42000000; - break; - case 32: // level 3.2 - bit_rate = 60000000; - break; - case 40: // level 4.0 - bit_rate = 60000000; - break; - case 41: // level 4.1 - bit_rate = 150000000; - break; - case 42: // level 4.2 - bit_rate = 150000000; - break; - case 50: // level 5.0 - bit_rate = 405000000; - break; - case 51: // level 5.1 - bit_rate = 720000000; - break; - default: - break; - } - break; - case 122: // high 4:2:2 profile - case 144: // high 4:4:4 profile - switch (level_idc) - { - case 10: // level 1.0 - bit_rate = 256000; - break; - case 11: // level 1b / 1.1 - bit_rate = constraint_set3_flag ? 512000 : 768000; - break; - case 12: // level 1.2 - bit_rate = 1536000; - break; - case 13: // level 1.3 - bit_rate = 3072000; - break; - case 20: // level 2.0 - bit_rate = 8000000; - break; - case 21: // level 2.1 - bit_rate = 16000000; - break; - case 22: // level 2.2 - bit_rate = 16000000; - break; - case 30: // level 3.0 - bit_rate = 40000000; - break; - case 31: // level 3.1 - bit_rate = 56000000; - break; - case 32: // level 3.2 - bit_rate = 80000000; - break; - case 40: // level 4.0 - bit_rate = 80000000; - break; - case 41: // level 4.1 - bit_rate = 200000000; - break; - case 42: // level 4.2 - bit_rate = 200000000; - break; - case 50: // level 5.0 - bit_rate = 540000000; - break; - case 51: // level 5.1 - bit_rate = 960000000; - break; - default: - break; - } - break; - default: - break; - } - if ((profile_idc == 100) || (profile_idc == 110) || (profile_idc == 122) || (profile_idc == 144)) - { - if (bs.getUeGolomb() == 3) // chroma_format_idc - bs.skipBit(); // residual_colour_transform_flag - bs.skipUeGolomb(); // bit_depth_luma_minus8 - bs.skipUeGolomb(); // bit_depth_chroma_minus8 - bs.skipBit(); // qpprime_y_zero_transform_bypass_flag - if (bs.getBit()) // seq_scaling_matrix_present_flag - { - for (i = 0; i < 8; ++i) - { - if (bs.getBit()) // seq_scaling_list_present_flag[i] - { - int last = 8, next = 8, size = (i < 6) ? 16 : 64; - for (j = 0; j < size; ++j) - { - if (next) - next = (last + bs.getSeGolomb()) & 0xff; - last = next ?: last; - } - } - } - } - } - bs.skipUeGolomb(); // log2_max_frame_num_minus4 - pic_order_cnt_type = bs.getUeGolomb(); // pic_order_cnt_type - if (pic_order_cnt_type == 0) - bs.skipUeGolomb(); // log2_max_pic_order_cnt_lsb_minus4 - else if (pic_order_cnt_type == 1) - { - bs.skipBit(); // delta_pic_order_always_zero - bs.skipSeGolomb(); // offset_for_non_ref_pic - bs.skipSeGolomb(); // offset_for_top_to_bottom_field - j = bs.getUeGolomb(); // num_ref_frames_in_pic_order_cnt_cycle - for (i = 0; i < j; ++i) - bs.skipSeGolomb(); // offset_for_ref_frame[i] - } - bs.skipUeGolomb(); // num_ref_frames - bs.skipBit(); // gaps_in_frame_num_value_allowed_flag - width = bs.getUeGolomb() + 1; // pic_width_in_mbs_minus1 - height = bs.getUeGolomb() + 1; // pic_height_in_mbs_minus1 - frame_mbs_only_flag = bs.getBit(); // frame_mbs_only_flag - width *= 16; - height *= 16 * (frame_mbs_only_flag ? 1 : 2); - if (!frame_mbs_only_flag) - mb_adaptive_frame_field_flag = bs.getBit(); // mb_adaptive_frame_field_flag - bs.skipBit(); // direct_8x8_inference_flag - if (bs.getBit()) // frame_cropping_flag - { - uint32_t crop_left, crop_right, crop_top, crop_bottom; - crop_left = bs.getUeGolomb(); // frame_crop_left_offset - crop_right = bs.getUeGolomb(); // frame_crop_rigth_offset - crop_top = bs.getUeGolomb(); // frame_crop_top_offset - crop_bottom = bs.getUeGolomb(); // frame_crop_bottom_offset - width -= 2 * (crop_left + crop_right); - if (frame_mbs_only_flag) - height -= 2 * (crop_top + crop_bottom); - else - height -= 4 * (crop_top + crop_bottom); - } - // VUI parameters - if (bs.getBit()) // vui_parameters_present_flag - { - if (bs.getBit()) // aspect_ratio_info_present - { - aspect_ratio_idc = bs.getU8(); // aspect_ratio_idc - if (aspect_ratio_idc == 255) // extended sar - { - bs.skipBits(16); // sar_width - bs.skipBits(16); // sar_height - } - } - if (bs.getBit()) // overscan_info_present_flag - bs.skipBit(); // overscan_approriate_flag - if (bs.getBit()) // video_signal_type_present_flag - { - video_format = bs.getBits(3); // video_format - bs.skipBit(); // video_full_range_flag - if (bs.getBit()) // colour_description_present_flag - { - bs.skipBits(8); // colour_primaries - bs.skipBits(8); // transfer_characteristics - bs.skipBits(8); // matrix_coefficients - } - } - if (bs.getBit()) // chroma_loc_info_present_flag - { - bs.skipUeGolomb(); // chroma_sample_loc_type_top_field - bs.skipUeGolomb(); // chroma_sample_loc_type_bottom_field - } - if (bs.getBit()) // timing_info_present_flag - { - uint32_t num_units_in_tick, time_scale; - num_units_in_tick = bs.getU32(); // num_units_in_tick - time_scale = bs.getU32(); // time_scale - if (num_units_in_tick > 0) - frame_rate = time_scale / num_units_in_tick; - bs.skipBit(); // fixed_frame_rate_flag - } - int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag - if (nal_hrd_parameters_present_flag) - { - int cpb_cnt_minus1; - cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 - bs.skipBits(4); // bit_rate_scale - bs.skipBits(4); // cpb_size_scale - for (int i = 0; i < cpb_cnt_minus1; ++i) - { - bs.skipUeGolomb(); // bit_rate_value_minus1[i] - bs.skipUeGolomb(); // cpb_size_value_minus1[i] - bs.skipBit(); // cbr_flag[i] - } - bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 - bs.skipBits(5); // cpb_removal_delay_length_minus1 - bs.skipBits(5); // dpb_output_delay_length_minus1 - time_offset_length = bs.getBits(5); // time_offset_length - } - int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag - if (vlc_hrd_parameters_present_flag) - { - int cpb_cnt_minus1; - cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 - bs.skipBits(4); // bit_rate_scale - bs.skipBits(4); // cpb_size_scale - for (int i = 0; i < cpb_cnt_minus1; ++i) - { - bs.skipUeGolomb(); // bit_rate_value_minus1[i] - bs.skipUeGolomb(); // cpb_size_value_minus1[i] - bs.skipBit(); // cbr_flag[i] - } - bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 - bs.skipBits(5); // cpb_removal_delay_length_minus1 - bs.skipBits(5); // dpb_output_delay_length_minus1 - time_offset_length = bs.getBits(5);// time_offset_length - } - cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag); - if (cpb_dpb_delays_present_flag) - bs.skipBit(); // low_delay_hrd_flag - pic_struct_present_flag = bs.getBit(); // pic_struct_present_flag - if (bs.getBit()) // bitstream_restriction_flag - { - bs.skipBit(); // motion_vectors_over_pic_boundaries_flag - bs.skipUeGolomb(); // max_bytes_per_pic_denom - bs.skipUeGolomb(); // max_bits_per_mb_denom - bs.skipUeGolomb(); // log2_max_mv_length_horizontal - bs.skipUeGolomb(); // log2_max_mv_length_vertical - bs.skipUeGolomb(); // num_reorder_frames - bs.skipUeGolomb(); // max_dec_frame_buffering - } - } - - if ((bs.getIndex() / 8)>0) - { - // set values - maContext->Video.Info.Width=width; - maContext->Video.Info.Height=height; - - switch (aspect_ratio_idc) - { - case 1: - maContext->Video.Info.AspectRatio.Num=1; - maContext->Video.Info.AspectRatio.Den=1; - break; - case 2: - maContext->Video.Info.AspectRatio.Num=12; - maContext->Video.Info.AspectRatio.Den=31; - break; - case 3: - maContext->Video.Info.AspectRatio.Num=10; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 4: - maContext->Video.Info.AspectRatio.Num=16; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 5: - maContext->Video.Info.AspectRatio.Num=40; - maContext->Video.Info.AspectRatio.Den=33; - break; - case 6: - maContext->Video.Info.AspectRatio.Num=24; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 7: - maContext->Video.Info.AspectRatio.Num=20; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 8: - maContext->Video.Info.AspectRatio.Num=32; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 9: - maContext->Video.Info.AspectRatio.Num=80; - maContext->Video.Info.AspectRatio.Den=33; - break; - case 10: - maContext->Video.Info.AspectRatio.Num=18; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 11: - maContext->Video.Info.AspectRatio.Num=15; - maContext->Video.Info.AspectRatio.Den=11; - break; - case 12: - maContext->Video.Info.AspectRatio.Num=64; - maContext->Video.Info.AspectRatio.Den=33; - break; - case 13: - maContext->Video.Info.AspectRatio.Num=160; - maContext->Video.Info.AspectRatio.Den=99; - break; - case 14: - maContext->Video.Info.AspectRatio.Num=4; - maContext->Video.Info.AspectRatio.Den=3; - break; - case 15: - maContext->Video.Info.AspectRatio.Num=3; - maContext->Video.Info.AspectRatio.Den=2; - break; - case 16: - maContext->Video.Info.AspectRatio.Num=2; - maContext->Video.Info.AspectRatio.Den=1; - break; - } - } - } -} - -void cMarkAdDecoder::FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) -{ - if ((!maContext) || (!pkt) || (!len)) return; - - maContext->Video.Info.Pict_Type=0; - - struct H262_SequenceHdr - { -unsigned Sync1: - 8; -unsigned Sync2: - 8; -unsigned Sync3: - 8; -unsigned Sync4: - 8; -unsigned WidthH: - 8; -unsigned HeightH: - 4; -unsigned WidthL: - 4; -unsigned HeightL: - 8; -unsigned FrameRateIndex: - 4; -unsigned AspectRatioIndex: - 4; - }; - - struct H262_PictureHdr - { -unsigned Sync1: - 8; -unsigned Sync2: - 8; -unsigned Sync3: - 8; -unsigned Sync4: - 8; -unsigned TemporalReferenceH: - 8; -unsigned VBVDelay: - 3; -unsigned CodingType: - 3; -unsigned TemporalReferenceL: - 8; - }; - - struct H262_SequenceHdr *seqhdr = (struct H262_SequenceHdr *) pkt; - struct H262_PictureHdr *pichdr = (struct H262_PictureHdr *) pkt; - - if (pichdr->Sync1==0 && pichdr->Sync2==0 && pichdr->Sync3==1 && pichdr->Sync4==0) - { - if (maContext->Video.Info.Height==0) return; - - switch (pichdr->CodingType) - { - case 1: - maContext->Video.Info.Pict_Type=MA_I_TYPE; - break; - case 2: - maContext->Video.Info.Pict_Type=MA_P_TYPE; - break; - case 3: - maContext->Video.Info.Pict_Type=MA_B_TYPE; - break; - case 4: - maContext->Video.Info.Pict_Type=MA_D_TYPE; - break; - default: - maContext->Video.Info.Pict_Type=0; - break; - } - } - - if (seqhdr->Sync1==0 && seqhdr->Sync2==0 && seqhdr->Sync3==1 && seqhdr->Sync4==0xb3) - { - - maContext->Video.Info.Height=(seqhdr->HeightH<<8)+seqhdr->HeightL; - maContext->Video.Info.Width=(seqhdr->WidthH<<4)+seqhdr->WidthL; - - switch (seqhdr->AspectRatioIndex) - { - case 1: - maContext->Video.Info.AspectRatio.Num=1; - maContext->Video.Info.AspectRatio.Den=1; - break; - case 2: - maContext->Video.Info.AspectRatio.Num=4; - maContext->Video.Info.AspectRatio.Den=3; - break; - case 3: - maContext->Video.Info.AspectRatio.Num=16; - maContext->Video.Info.AspectRatio.Den=9; - break; - case 4: - maContext->Video.Info.AspectRatio.Num=11; // actually 2.21:1 - maContext->Video.Info.AspectRatio.Den=5; - break; - default: - break; - } - } - -} - cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) { recvnumber=RecvNumber; -#ifdef HAVE_AVCODEC avcodec_init(); avcodec_register_all(); @@ -737,7 +26,8 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) cpucount=CPU_COUNT(&cpumask); } - isyslog("markad [%i]: using ffmpeg with %i threads",recvnumber,cpucount); + isyslog("markad [%i]: using libavcodec.so.%s with %i threads",recvnumber, + AV_STRINGIFY(LIBAVCODEC_VERSION),cpucount); CodecID mp2_codecid=CODEC_ID_MP2; AVCodec *mp2_codec= avcodec_find_decoder(mp2_codecid); @@ -851,13 +141,10 @@ cMarkAdDecoder::cMarkAdDecoder(int RecvNumber, bool useH264, bool hasAC3) esyslog("markad [%i]: codec 0x%05x not found",recvnumber,video_codecid); video_context=NULL; } - memset(temp_pictureplane,0,sizeof(temp_pictureplane)); -#endif } cMarkAdDecoder::~cMarkAdDecoder() { -#ifdef HAVE_AVCODEC if (video_context) { avcodec_close(video_context); @@ -877,12 +164,10 @@ cMarkAdDecoder::~cMarkAdDecoder() av_free(mp2_context); } SetVideoInfos(NULL,NULL,NULL,NULL); -#endif } bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen) { -#ifdef HAVE_AVCODEC if (!mp2_context) return false; AVPacket avpkt; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(25<<8)+0) @@ -920,12 +205,8 @@ bool cMarkAdDecoder::DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen } } return ret; -#else - return true; -#endif } -#ifdef HAVE_AVCODEC bool cMarkAdDecoder::SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context) { if ((!maContext) || (!Audio_Context)) return false; @@ -933,11 +214,9 @@ bool cMarkAdDecoder::SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Aud maContext->Audio.Info.Channels = Audio_Context->channels; return true; } -#endif bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen) { -#ifdef HAVE_AVCODEC if (!ac3_context) return false; AVPacket avpkt; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(25<<8)+0) @@ -975,12 +254,8 @@ bool cMarkAdDecoder::DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen } } return ret; -#else - return true; -#endif } -#ifdef HAVE_AVCODEC void cMarkAdDecoder::PAR2DAR(AVRational a, AVRational *erg) { av_reduce(&erg->num,&erg->den,video_context->width*a.num, @@ -989,25 +264,13 @@ void cMarkAdDecoder::PAR2DAR(AVRational a, AVRational *erg) bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Video_Context, AVFrame *Video_Frame, AVRational *DAR) { - for (int i=0; i<4; i++) - { - if (temp_pictureplane[i]) - { - free(temp_pictureplane[i]); - temp_pictureplane[i]=NULL; - } - } - if ((!maContext) || (!Video_Context) || (!Video_Frame)) return false; maContext->Video.Data.Valid=false; for (int i=0; i<4; i++) { if (Video_Frame->data[i]) { - temp_pictureplane[i]=(uchar *) malloc(Video_Frame->linesize[i]); - if (!temp_pictureplane[i]) return false; - memcpy(temp_pictureplane[i],Video_Frame->data[i],Video_Frame->linesize[i]); - maContext->Video.Data.Plane[i]=temp_pictureplane[i]; + maContext->Video.Data.Plane[i]=Video_Frame->data[i]; maContext->Video.Data.PlaneLinesize[i]=Video_Frame->linesize[i]; } } @@ -1050,11 +313,9 @@ bool cMarkAdDecoder::SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Vide maContext->Video.Data.Valid=true; return true; } -#endif bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen) { -#ifdef HAVE_AVCODEC AVPacket avpkt; #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(25<<8)+0) av_init_packet(&avpkt); @@ -1096,122 +357,4 @@ bool cMarkAdDecoder::DecodeVideo(MarkAdContext *maContext,uchar *pkt, int plen) } } return ret; -#else - if (maContext->Video.Info.Pict_Type!=0) - { - return true; - } - else - { - return false; - } -#endif -} - -// taken from femon -int cMarkAdDecoder::nalUnescape(uint8_t *dst, const uint8_t *src, int len) -{ - int s = 0, d = 0; - - while (s < len) - { - if (!src[s] && !src[s + 1]) - { - // hit 00 00 xx - dst[d] = dst[d + 1] = 0; - s += 2; - d += 2; - if (src[s] == 3) - { - s++; // 00 00 03 xx --> 00 00 xx - if (s >= len) - return d; - } - } - dst[d++] = src[s++]; - } - - return d; -} - -cBitStream::cBitStream(const uint8_t *buf, const int len) - : data(buf), - count(len), - index(0) -{ -} - -cBitStream::~cBitStream() -{ -} - -int cBitStream::getBit() -{ - if (index >= count) - return (1); // -> no infinite colomb's ... - - int r = (data[index >> 3] >> (7 - (index & 7))) & 1; - ++index; - - return (r); -} - -uint32_t cBitStream::getBits(uint32_t n) -{ - uint32_t r = 0; - - while (n--) - r = (r | (getBit() << n)); - - return (r); -} - -void cBitStream::skipBits(uint32_t n) -{ - index += n; -} - -uint32_t cBitStream::getUeGolomb() -{ - int n = 0; - - while (!getBit() && (n < 32)) - n++; - - return (n ? ((1 << n) - 1) + getBits(n) : 0); -} - -int32_t cBitStream::getSeGolomb() -{ - uint32_t r = getUeGolomb() + 1; - - return ((r & 1) ? -(r >> 1) : (r >> 1)); -} - -void cBitStream::skipGolomb() -{ - int n = 0; - - while (!getBit() && (n < 32)) - n++; - - skipBits(n); -} - -void cBitStream::skipUeGolomb() -{ - skipGolomb(); -} - -void cBitStream::skipSeGolomb() -{ - skipGolomb(); -} - -void cBitStream::byteAlign() -{ - int n = index % 8; - - if (n > 0) - skipBits(8 - n); } @@ -27,7 +27,6 @@ typedef unsigned char uchar; #endif -#ifdef HAVE_AVCODEC extern "C" { #include <libavcodec/avcodec.h> @@ -36,7 +35,6 @@ extern "C" #include <libavformat/avformat.h> #endif } -#endif #include "global.h" @@ -44,100 +42,24 @@ class cMarkAdDecoder { private: int recvnumber; -#ifdef HAVE_AVCODEC AVCodecContext *ac3_context; AVCodecContext *mp2_context; AVCodecContext *video_context; AVFrame *video_frame; - uchar *temp_pictureplane[4]; bool SetAudioInfos(MarkAdContext *maContext, AVCodecContext *Audio_Context); void PAR2DAR(AVRational a, AVRational *erg); bool SetVideoInfos(MarkAdContext *maContext,AVCodecContext *Video_Context, AVFrame *Video_Frame, AVRational *DAR); -#endif - // taken from femon - enum - { - NAL_SEI = 0x06, // Supplemental Enhancement Information - NAL_SPS = 0x07, // Sequence Parameter Set - NAL_AUD = 0x09, // Access Unit Delimiter - NAL_END_SEQ = 0x0A // End of Sequence - }; - int nalUnescape(uint8_t *dst, const uint8_t *src, int len); - - void FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); - void FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); public: - void FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len); bool DecodeVideo(MarkAdContext *maContext, uchar *pkt, int plen); bool DecodeMP2(MarkAdContext *maContext, uchar *espkt, int eslen); - void FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen); bool DecodeAC3(MarkAdContext *maContext, uchar *espkt, int eslen); cMarkAdDecoder(int recvnumber, bool useH264, bool hasAC3); ~cMarkAdDecoder(); }; -// taken from femon -class cBitStream -{ -private: - const uint8_t *data; - int count; // in bits - int index; // in bits - -public: - cBitStream(const uint8_t *buf, const int len); - ~cBitStream(); - - int getBit(); - uint32_t getBits(uint32_t n); - void skipBits(uint32_t n); - uint32_t getUeGolomb(); - int32_t getSeGolomb(); - void skipGolomb(); - void skipUeGolomb(); - void skipSeGolomb(); - void byteAlign(); - - void skipBit() - { - skipBits(1); - } - uint32_t getU8() - { - return getBits(8); - } - uint32_t getU16() - { - return ((getBits(8) << 8) | getBits(8)); - } - uint32_t getU24() - { - return ((getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); - } - uint32_t getU32() - { - return ((getBits(8) << 24) | (getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); - } - bool isEOF() - { - return (index >= count); - } - void reset() - { - index = 0; - } - int getIndex() - { - return (isEOF() ? count : index); - } - const uint8_t *getData() - { - return (isEOF() ? NULL : data + (index / 8)); - } -}; #endif diff --git a/markad-standalone.cpp b/markad-standalone.cpp index 94c0d22..2b47d33 100644 --- a/markad-standalone.cpp +++ b/markad-standalone.cpp @@ -87,15 +87,15 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) { if (pkt) { - decoder->FindVideoInfos(&macontext,pkt,pktlen); if (decoder->DecodeVideo(&macontext,pkt,pktlen)) { if (macontext.Video.Info.Pict_Type==MA_I_TYPE) { lastiframe=framecnt; - mark=video->Process(lastiframe); - AddMark(mark); } + mark=video->Process(framecnt); + AddMark(mark); + framecnt++; } } @@ -155,7 +155,6 @@ bool cMarkAdStandalone::ProcessFile(const char *Directory, int Number) { if (pkt) { - decoder->FindAC3AudioInfos(&macontext,pkt,pktlen); if (decoder->DecodeAC3(&macontext,pkt,pktlen)) { mark=audio->Process(lastiframe); @@ -233,14 +232,19 @@ bool cMarkAdStandalone::CheckPATPMT(const char *Directory) free(buf); if (fd==-1) return false; - uchar patpmt[376]; + uchar patpmt_buf[564]; + uchar *patpmt; - if (read(fd,patpmt,sizeof(patpmt))!=sizeof(patpmt)) + if (read(fd,patpmt_buf,sizeof(patpmt_buf))!=sizeof(patpmt_buf)) { close(fd); return false; } close(fd); + patpmt=patpmt_buf; + + if ((patpmt[0]==0x47) && ((patpmt[1] & 0x5F)==0x40) && (patpmt[2]==0x11) && + ((patpmt[3] & 0x10)==0x10)) patpmt+=188; // skip SDT // some checks if ((patpmt[0]!=0x47) || (patpmt[188]!=0x47)) return false; // no TS-Sync @@ -398,11 +402,21 @@ cMarkAdStandalone::cMarkAdStandalone(const char *Directory) ac3_demux=NULL; } - decoder = new cMarkAdDecoder(recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264, - macontext.General.DPid.Num!=0); - video = new cMarkAdVideo(recvnumber,&macontext); - audio = new cMarkAdAudio(recvnumber,&macontext); - common = new cMarkAdCommon(recvnumber,&macontext); + if (!abort) + { + decoder = new cMarkAdDecoder(recvnumber,macontext.General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264, + macontext.General.DPid.Num!=0); + video = new cMarkAdVideo(recvnumber,&macontext); + audio = new cMarkAdAudio(recvnumber,&macontext); + common = new cMarkAdCommon(recvnumber,&macontext); + } + else + { + decoder=NULL; + video=NULL; + audio=NULL; + common=NULL; + } framecnt=0; } @@ -11,8 +11,8 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *Timer) : cReceiver(Timer->Channel()->GetChannelID(), -1, - Timer->Channel()->Vpid(),Timer->Channel()->Apids(), - Timer->Channel()->Dpids()),cThread("markad"), + Timer->Channel()->Vpid(),Timer->Channel()->Dpids()), + cThread("markad"), buffer(MEGATS(3)), running(false) // 3MB Buffer { if ((!Filename) || (!Timer)) return; @@ -72,16 +72,6 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T video_demux=NULL; } - if (macontext.General.APid.Num) - { - dsyslog("markad [%i]: using MP2",recvnumber); - mp2_demux = new cMarkAdDemux(RecvNumber); - } - else - { - mp2_demux = NULL; - } - if (macontext.General.DPid.Num) { dsyslog("markad [%i]: using AC3",recvnumber); @@ -101,7 +91,7 @@ cMarkAdReceiver::cMarkAdReceiver(int RecvNumber, const char *Filename, cTimer *T audio=NULL; } - decoder=new cMarkAdDecoder(RecvNumber,useH264,macontext.General.DPid.Num!=0); + streaminfo=new cMarkAdStreamInfo; common=new cMarkAdCommon(RecvNumber,&macontext); marks.Load(Filename); @@ -122,9 +112,8 @@ cMarkAdReceiver::~cMarkAdReceiver() buffer.Clear(); if (video_demux) delete video_demux; - if (mp2_demux) delete mp2_demux; if (ac3_demux) delete ac3_demux; - if (decoder) delete decoder; + if (streaminfo) delete streaminfo; if (video) delete video; if (audio) delete audio; if (common) delete common; @@ -300,7 +289,7 @@ void cMarkAdReceiver::Action() AddMark(mark,0); } - if ((video_demux) && (decoder) && (video)) + if ((video_demux) && (streaminfo) && (video)) { cTimeMs t; uchar *pkt; @@ -320,23 +309,20 @@ void cMarkAdReceiver::Action() { if (pkt) { - decoder->FindVideoInfos(&macontext,pkt,pktlen); - if (decoder->DecodeVideo(&macontext,pkt,pktlen)) + streaminfo->FindVideoInfos(&macontext,pkt,pktlen); + if (macontext.Video.Info.Pict_Type==MA_I_TYPE) { - if (macontext.Video.Info.Pict_Type==MA_I_TYPE) + if (framecnt==-1) + { + framecnt=0; + } + else { - if (framecnt==-1) - { - framecnt=0; - } - else - { - mark=video->Process(lastiframe); - AddMark(mark,3); - } + mark=video->Process(lastiframe); + AddMark(mark,3); } - if (framecnt!=-1) framecnt++; } + if (framecnt!=-1) framecnt++; } tspkt+=len; tslen-=len; @@ -349,38 +335,7 @@ void cMarkAdReceiver::Action() } } - if ((mp2_demux) && (decoder) && (audio)) - { - uchar *pkt; - int pktlen; - - uchar *tspkt = frame->Data(); - int tslen = frame->Count(); - - while (tslen>0) - { - int len=mp2_demux->Process(macontext.General.APid,tspkt,tslen,&pkt,&pktlen); - if (len<0) - { - break; - } - else - { - if (pkt) - { - if (decoder->DecodeMP2(&macontext,pkt,pktlen)) - { - mark=audio->Process(lastiframe); - AddMark(mark,1); - } - } - tspkt+=len; - tslen-=len; - } - } - } - - if ((ac3_demux) && (decoder) && (audio)) + if ((ac3_demux) && (streaminfo) && (audio)) { uchar *pkt; int pktlen; @@ -399,12 +354,9 @@ void cMarkAdReceiver::Action() { if (pkt) { - decoder->FindAC3AudioInfos(&macontext,pkt,pktlen); - if (decoder->DecodeAC3(&macontext,pkt,pktlen)) - { - mark=audio->Process(lastiframe); - AddMark(mark,2); - } + streaminfo->FindAC3AudioInfos(&macontext,pkt,pktlen); + mark=audio->Process(lastiframe); + AddMark(mark,2); } tspkt+=len; tslen-=len; @@ -16,7 +16,7 @@ #include <vdr/recording.h> #include "demux.h" -#include "decoder.h" +#include "streaminfo.h" #include "audio.h" #include "video.h" #include "common.h" @@ -66,13 +66,12 @@ private: int LastIFrame(); MarkAdContext macontext; - cMarkAdDecoder *decoder; + cMarkAdStreamInfo *streaminfo; cMarkAdCommon *common; cMarkAdAudio *audio; cMarkAdVideo *video; cMarkAdDemux *video_demux; - cMarkAdDemux *mp2_demux; cMarkAdDemux *ac3_demux; void AddMark(MarkAdMark *mark, int Priority); diff --git a/streaminfo.cpp b/streaminfo.cpp new file mode 100644 index 0000000..2c0b6a3 --- /dev/null +++ b/streaminfo.cpp @@ -0,0 +1,827 @@ +/* + * streaminfo.cpp: A program for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include "streaminfo.h" + +void cMarkAdStreamInfo::FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen) +{ + if ((!maContext) || (!espkt)) return; + +#pragma pack(1) + struct AC3HDR + { +unsigned Sync1: + 8; +unsigned Sync2: + 8; +unsigned CrcH: + 8; +unsigned CrcL: + 8; +unsigned FrameSizeIndex: + 6; +unsigned SampleRateIndex: + 2; +unsigned BsMod: + 3; +unsigned BsID: + 5; +unsigned LFE_Mix_VarField: + 5; +unsigned AcMod: + 3; + }; +#pragma pack() + + struct AC3HDR *ac3hdr = (struct AC3HDR *) espkt; + + if ((ac3hdr->Sync1==0x0b) && (ac3hdr->Sync2==0x77)) + { + // some extra checks + if (ac3hdr->SampleRateIndex==3) return; // reserved + if (ac3hdr->FrameSizeIndex>=38) return; // reserved + + maContext->Audio.Info.Channels=0; + int lfe_bitmask = 0x0; + + switch (ac3hdr->AcMod) + { + case 0: + maContext->Audio.Info.Channels=2; + lfe_bitmask=0x10; + break; + case 1: + maContext->Audio.Info.Channels=1; + lfe_bitmask=0x10; + break; + case 2: + maContext->Audio.Info.Channels=2; + lfe_bitmask=0x4; + break; + case 3: + maContext->Audio.Info.Channels=3; + lfe_bitmask=0x4; + break; + case 4: + maContext->Audio.Info.Channels=3; + lfe_bitmask=0x4; + break; + case 5: + maContext->Audio.Info.Channels=4; + lfe_bitmask=0x1; + break; + case 6: + maContext->Audio.Info.Channels=4; + lfe_bitmask=0x4; + break; + case 7: + maContext->Audio.Info.Channels=5; + lfe_bitmask=0x1; + break; + } + + if ((ac3hdr->LFE_Mix_VarField & lfe_bitmask)==lfe_bitmask) + maContext->Audio.Info.Channels++; + } + +} + +void cMarkAdStreamInfo::FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +{ + if ((!maContext) || (!pkt) || (!len)) return; + if (!maContext->General.VPid.Type) return; + + if (maContext->General.VPid.Type==MARKAD_PIDTYPE_VIDEO_H264) + { + FindH264VideoInfos(maContext, pkt, len); + } + else + { + FindH262VideoInfos(maContext, pkt, len); + } +} + +void cMarkAdStreamInfo::FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +{ + if ((!maContext) || (!pkt) || (!len)) return; + + maContext->Video.Info.Pict_Type=0; + + if ((pkt[3] & 0x1F)==NAL_AUD) + { + switch (pkt[4] >> 5) + { + case 0: + case 3: + case 5: // I_FRAME + maContext->Video.Info.Pict_Type=MA_I_TYPE; + break; + case 1: + case 4: + case 6: // P_FRAME; + maContext->Video.Info.Pict_Type=MA_P_TYPE; + break; + case 2: + case 7: // B_FRAME; + maContext->Video.Info.Pict_Type=MA_B_TYPE; + break; + default: // NO_PICTURE; + maContext->Video.Info.Pict_Type=0; + break; + } + } + + if ((pkt[3] & 0x1F)==NAL_SPS) + { + uint8_t nal_data[len]; + const uint8_t *end = pkt + len; + int nal_len = nalUnescape(nal_data, pkt + 4, int(end - pkt - 4)); + + int profile_idc, level_idc, constraint_set3_flag, pic_order_cnt_type, i, j; + cBitStream bs(nal_data, nal_len); + + uint32_t width=0; + uint32_t height=0; + uint32_t aspect_ratio_idc=0; + uint32_t video_format=0; + double frame_rate=0; + double bit_rate=0; + bool cpb_dpb_delays_present_flag=false; + bool pic_struct_present_flag=false; + bool frame_mbs_only_flag=false; + bool mb_adaptive_frame_field_flag=false; + uint32_t time_offset_length=0; + + profile_idc = bs.getU8(); // profile_idc + bs.skipBit(); // constraint_set0_flag + bs.skipBit(); // constraint_set1_flag + bs.skipBit(); // constraint_set2_flag + constraint_set3_flag = bs.getBit(); // constraint_set3_flag + bs.skipBits(4); // reserved_zero_4bits + level_idc = bs.getU8(); // level_idc + bs.skipUeGolomb(); // seq_parameter_set_id + + switch (profile_idc) + { + case 66: // baseline profile + case 77: // main profile + case 88: // extended profile + switch (level_idc) + { + case 10: // level 1.0 + bit_rate = 64000; + break; + case 11: // level 1b / 1.1 + bit_rate = constraint_set3_flag ? 128000 : 192000; + break; + case 12: // level 1.2 + bit_rate = 384000; + break; + case 13: // level 1.3 + bit_rate = 768000; + break; + case 20: // level 2.0 + bit_rate = 2000000; + break; + case 21: // level 2.1 + bit_rate = 4000000; + break; + case 22: // level 2.2 + bit_rate = 4000000; + break; + case 30: // level 3.0 + bit_rate = 10000000; + break; + case 31: // level 3.1 + bit_rate = 14000000; + break; + case 32: // level 3.2 + bit_rate = 20000000; + break; + case 40: // level 4.0 + bit_rate = 20000000; + break; + case 41: // level 4.1 + bit_rate = 50000000; + break; + case 42: // level 4.2 + bit_rate = 50000000; + break; + case 50: // level 5.0 + bit_rate = 135000000; + break; + case 51: // level 5.1 + bit_rate = 240000000; + break; + default: + break; + } + break; + case 100: // high profile + switch (level_idc) + { + case 10: // level 1.0 + bit_rate = 80000; + break; + case 11: // level 1b / 1.1 + bit_rate = constraint_set3_flag ? 160000 : 240000; + break; + case 12: // level 1.2 + bit_rate = 480000; + break; + case 13: // level 1.3 + bit_rate = 960000; + break; + case 20: // level 2.0 + bit_rate = 2500000; + break; + case 21: // level 2.1 + bit_rate = 5000000; + break; + case 22: // level 2.2 + bit_rate = 5000000; + break; + case 30: // level 3.0 + bit_rate = 12500000; + break; + case 31: // level 3.1 + bit_rate = 17500000; + break; + case 32: // level 3.2 + bit_rate = 25000000; + break; + case 40: // level 4.0 + bit_rate = 25000000; + break; + case 41: // level 4.1 + bit_rate = 62500000; + break; + case 42: // level 4.2 + bit_rate = 62500000; + break; + case 50: // level 5.0 + bit_rate = 168750000; + break; + case 51: // level 5.1 + bit_rate = 300000000; + break; + default: + break; + } + break; + case 110: // high 10 profile + switch (level_idc) + { + case 10: // level 1.0 + bit_rate = 192000; + break; + case 11: // level 1b / 1.1 + bit_rate = constraint_set3_flag ? 384000 : 576000; + break; + case 12: // level 1.2 + bit_rate = 115200; + break; + case 13: // level 1.3 + bit_rate = 2304000; + break; + case 20: // level 2.0 + bit_rate = 6000000; + break; + case 21: // level 2.1 + bit_rate = 12000000; + break; + case 22: // level 2.2 + bit_rate = 12000000; + break; + case 30: // level 3.0 + bit_rate = 30000000; + break; + case 31: // level 3.1 + bit_rate = 42000000; + break; + case 32: // level 3.2 + bit_rate = 60000000; + break; + case 40: // level 4.0 + bit_rate = 60000000; + break; + case 41: // level 4.1 + bit_rate = 150000000; + break; + case 42: // level 4.2 + bit_rate = 150000000; + break; + case 50: // level 5.0 + bit_rate = 405000000; + break; + case 51: // level 5.1 + bit_rate = 720000000; + break; + default: + break; + } + break; + case 122: // high 4:2:2 profile + case 144: // high 4:4:4 profile + switch (level_idc) + { + case 10: // level 1.0 + bit_rate = 256000; + break; + case 11: // level 1b / 1.1 + bit_rate = constraint_set3_flag ? 512000 : 768000; + break; + case 12: // level 1.2 + bit_rate = 1536000; + break; + case 13: // level 1.3 + bit_rate = 3072000; + break; + case 20: // level 2.0 + bit_rate = 8000000; + break; + case 21: // level 2.1 + bit_rate = 16000000; + break; + case 22: // level 2.2 + bit_rate = 16000000; + break; + case 30: // level 3.0 + bit_rate = 40000000; + break; + case 31: // level 3.1 + bit_rate = 56000000; + break; + case 32: // level 3.2 + bit_rate = 80000000; + break; + case 40: // level 4.0 + bit_rate = 80000000; + break; + case 41: // level 4.1 + bit_rate = 200000000; + break; + case 42: // level 4.2 + bit_rate = 200000000; + break; + case 50: // level 5.0 + bit_rate = 540000000; + break; + case 51: // level 5.1 + bit_rate = 960000000; + break; + default: + break; + } + break; + default: + break; + } + if ((profile_idc == 100) || (profile_idc == 110) || (profile_idc == 122) || (profile_idc == 144)) + { + if (bs.getUeGolomb() == 3) // chroma_format_idc + bs.skipBit(); // residual_colour_transform_flag + bs.skipUeGolomb(); // bit_depth_luma_minus8 + bs.skipUeGolomb(); // bit_depth_chroma_minus8 + bs.skipBit(); // qpprime_y_zero_transform_bypass_flag + if (bs.getBit()) // seq_scaling_matrix_present_flag + { + for (i = 0; i < 8; ++i) + { + if (bs.getBit()) // seq_scaling_list_present_flag[i] + { + int last = 8, next = 8, size = (i < 6) ? 16 : 64; + for (j = 0; j < size; ++j) + { + if (next) + next = (last + bs.getSeGolomb()) & 0xff; + last = next ?: last; + } + } + } + } + } + bs.skipUeGolomb(); // log2_max_frame_num_minus4 + pic_order_cnt_type = bs.getUeGolomb(); // pic_order_cnt_type + if (pic_order_cnt_type == 0) + bs.skipUeGolomb(); // log2_max_pic_order_cnt_lsb_minus4 + else if (pic_order_cnt_type == 1) + { + bs.skipBit(); // delta_pic_order_always_zero + bs.skipSeGolomb(); // offset_for_non_ref_pic + bs.skipSeGolomb(); // offset_for_top_to_bottom_field + j = bs.getUeGolomb(); // num_ref_frames_in_pic_order_cnt_cycle + for (i = 0; i < j; ++i) + bs.skipSeGolomb(); // offset_for_ref_frame[i] + } + bs.skipUeGolomb(); // num_ref_frames + bs.skipBit(); // gaps_in_frame_num_value_allowed_flag + width = bs.getUeGolomb() + 1; // pic_width_in_mbs_minus1 + height = bs.getUeGolomb() + 1; // pic_height_in_mbs_minus1 + frame_mbs_only_flag = bs.getBit(); // frame_mbs_only_flag + width *= 16; + height *= 16 * (frame_mbs_only_flag ? 1 : 2); + if (!frame_mbs_only_flag) + mb_adaptive_frame_field_flag = bs.getBit(); // mb_adaptive_frame_field_flag + bs.skipBit(); // direct_8x8_inference_flag + if (bs.getBit()) // frame_cropping_flag + { + uint32_t crop_left, crop_right, crop_top, crop_bottom; + crop_left = bs.getUeGolomb(); // frame_crop_left_offset + crop_right = bs.getUeGolomb(); // frame_crop_rigth_offset + crop_top = bs.getUeGolomb(); // frame_crop_top_offset + crop_bottom = bs.getUeGolomb(); // frame_crop_bottom_offset + width -= 2 * (crop_left + crop_right); + if (frame_mbs_only_flag) + height -= 2 * (crop_top + crop_bottom); + else + height -= 4 * (crop_top + crop_bottom); + } + // VUI parameters + if (bs.getBit()) // vui_parameters_present_flag + { + if (bs.getBit()) // aspect_ratio_info_present + { + aspect_ratio_idc = bs.getU8(); // aspect_ratio_idc + if (aspect_ratio_idc == 255) // extended sar + { + bs.skipBits(16); // sar_width + bs.skipBits(16); // sar_height + } + } + if (bs.getBit()) // overscan_info_present_flag + bs.skipBit(); // overscan_approriate_flag + if (bs.getBit()) // video_signal_type_present_flag + { + video_format = bs.getBits(3); // video_format + bs.skipBit(); // video_full_range_flag + if (bs.getBit()) // colour_description_present_flag + { + bs.skipBits(8); // colour_primaries + bs.skipBits(8); // transfer_characteristics + bs.skipBits(8); // matrix_coefficients + } + } + if (bs.getBit()) // chroma_loc_info_present_flag + { + bs.skipUeGolomb(); // chroma_sample_loc_type_top_field + bs.skipUeGolomb(); // chroma_sample_loc_type_bottom_field + } + if (bs.getBit()) // timing_info_present_flag + { + uint32_t num_units_in_tick, time_scale; + num_units_in_tick = bs.getU32(); // num_units_in_tick + time_scale = bs.getU32(); // time_scale + if (num_units_in_tick > 0) + frame_rate = time_scale / num_units_in_tick; + bs.skipBit(); // fixed_frame_rate_flag + } + int nal_hrd_parameters_present_flag = bs.getBit(); // nal_hrd_parameters_present_flag + if (nal_hrd_parameters_present_flag) + { + int cpb_cnt_minus1; + cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 + bs.skipBits(4); // bit_rate_scale + bs.skipBits(4); // cpb_size_scale + for (int i = 0; i < cpb_cnt_minus1; ++i) + { + bs.skipUeGolomb(); // bit_rate_value_minus1[i] + bs.skipUeGolomb(); // cpb_size_value_minus1[i] + bs.skipBit(); // cbr_flag[i] + } + bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 + bs.skipBits(5); // cpb_removal_delay_length_minus1 + bs.skipBits(5); // dpb_output_delay_length_minus1 + time_offset_length = bs.getBits(5); // time_offset_length + } + int vlc_hrd_parameters_present_flag = bs.getBit(); // vlc_hrd_parameters_present_flag + if (vlc_hrd_parameters_present_flag) + { + int cpb_cnt_minus1; + cpb_cnt_minus1 = bs.getUeGolomb(); // cpb_cnt_minus1 + bs.skipBits(4); // bit_rate_scale + bs.skipBits(4); // cpb_size_scale + for (int i = 0; i < cpb_cnt_minus1; ++i) + { + bs.skipUeGolomb(); // bit_rate_value_minus1[i] + bs.skipUeGolomb(); // cpb_size_value_minus1[i] + bs.skipBit(); // cbr_flag[i] + } + bs.skipBits(5); // initial_cpb_removal_delay_length_minus1 + bs.skipBits(5); // cpb_removal_delay_length_minus1 + bs.skipBits(5); // dpb_output_delay_length_minus1 + time_offset_length = bs.getBits(5);// time_offset_length + } + cpb_dpb_delays_present_flag = (nal_hrd_parameters_present_flag | vlc_hrd_parameters_present_flag); + if (cpb_dpb_delays_present_flag) + bs.skipBit(); // low_delay_hrd_flag + pic_struct_present_flag = bs.getBit(); // pic_struct_present_flag + if (bs.getBit()) // bitstream_restriction_flag + { + bs.skipBit(); // motion_vectors_over_pic_boundaries_flag + bs.skipUeGolomb(); // max_bytes_per_pic_denom + bs.skipUeGolomb(); // max_bits_per_mb_denom + bs.skipUeGolomb(); // log2_max_mv_length_horizontal + bs.skipUeGolomb(); // log2_max_mv_length_vertical + bs.skipUeGolomb(); // num_reorder_frames + bs.skipUeGolomb(); // max_dec_frame_buffering + } + } + + if ((bs.getIndex() / 8)>0) + { + // set values + maContext->Video.Info.Width=width; + maContext->Video.Info.Height=height; + + switch (aspect_ratio_idc) + { + case 1: + maContext->Video.Info.AspectRatio.Num=1; + maContext->Video.Info.AspectRatio.Den=1; + break; + case 2: + maContext->Video.Info.AspectRatio.Num=12; + maContext->Video.Info.AspectRatio.Den=31; + break; + case 3: + maContext->Video.Info.AspectRatio.Num=10; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 4: + maContext->Video.Info.AspectRatio.Num=16; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 5: + maContext->Video.Info.AspectRatio.Num=40; + maContext->Video.Info.AspectRatio.Den=33; + break; + case 6: + maContext->Video.Info.AspectRatio.Num=24; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 7: + maContext->Video.Info.AspectRatio.Num=20; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 8: + maContext->Video.Info.AspectRatio.Num=32; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 9: + maContext->Video.Info.AspectRatio.Num=80; + maContext->Video.Info.AspectRatio.Den=33; + break; + case 10: + maContext->Video.Info.AspectRatio.Num=18; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 11: + maContext->Video.Info.AspectRatio.Num=15; + maContext->Video.Info.AspectRatio.Den=11; + break; + case 12: + maContext->Video.Info.AspectRatio.Num=64; + maContext->Video.Info.AspectRatio.Den=33; + break; + case 13: + maContext->Video.Info.AspectRatio.Num=160; + maContext->Video.Info.AspectRatio.Den=99; + break; + case 14: + maContext->Video.Info.AspectRatio.Num=4; + maContext->Video.Info.AspectRatio.Den=3; + break; + case 15: + maContext->Video.Info.AspectRatio.Num=3; + maContext->Video.Info.AspectRatio.Den=2; + break; + case 16: + maContext->Video.Info.AspectRatio.Num=2; + maContext->Video.Info.AspectRatio.Den=1; + break; + } + } + } +} + +void cMarkAdStreamInfo::FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len) +{ + if ((!maContext) || (!pkt) || (!len)) return; + + maContext->Video.Info.Pict_Type=0; + + struct H262_SequenceHdr + { +unsigned Sync1: + 8; +unsigned Sync2: + 8; +unsigned Sync3: + 8; +unsigned Sync4: + 8; +unsigned WidthH: + 8; +unsigned HeightH: + 4; +unsigned WidthL: + 4; +unsigned HeightL: + 8; +unsigned FrameRateIndex: + 4; +unsigned AspectRatioIndex: + 4; + }; + + struct H262_PictureHdr + { +unsigned Sync1: + 8; +unsigned Sync2: + 8; +unsigned Sync3: + 8; +unsigned Sync4: + 8; +unsigned TemporalReferenceH: + 8; +unsigned VBVDelay: + 3; +unsigned CodingType: + 3; +unsigned TemporalReferenceL: + 8; + }; + + struct H262_SequenceHdr *seqhdr = (struct H262_SequenceHdr *) pkt; + struct H262_PictureHdr *pichdr = (struct H262_PictureHdr *) pkt; + + if (pichdr->Sync1==0 && pichdr->Sync2==0 && pichdr->Sync3==1 && pichdr->Sync4==0) + { + if (maContext->Video.Info.Height==0) return; + + switch (pichdr->CodingType) + { + case 1: + maContext->Video.Info.Pict_Type=MA_I_TYPE; + break; + case 2: + maContext->Video.Info.Pict_Type=MA_P_TYPE; + break; + case 3: + maContext->Video.Info.Pict_Type=MA_B_TYPE; + break; + case 4: + maContext->Video.Info.Pict_Type=MA_D_TYPE; + break; + default: + maContext->Video.Info.Pict_Type=0; + break; + } + } + + if (seqhdr->Sync1==0 && seqhdr->Sync2==0 && seqhdr->Sync3==1 && seqhdr->Sync4==0xb3) + { + + maContext->Video.Info.Height=(seqhdr->HeightH<<8)+seqhdr->HeightL; + maContext->Video.Info.Width=(seqhdr->WidthH<<4)+seqhdr->WidthL; + + switch (seqhdr->AspectRatioIndex) + { + case 1: + maContext->Video.Info.AspectRatio.Num=1; + maContext->Video.Info.AspectRatio.Den=1; + break; + case 2: + maContext->Video.Info.AspectRatio.Num=4; + maContext->Video.Info.AspectRatio.Den=3; + break; + case 3: + maContext->Video.Info.AspectRatio.Num=16; + maContext->Video.Info.AspectRatio.Den=9; + break; + case 4: + maContext->Video.Info.AspectRatio.Num=11; // actually 2.21:1 + maContext->Video.Info.AspectRatio.Den=5; + break; + default: + break; + } + } + +} + +// taken from femon +int cMarkAdStreamInfo::nalUnescape(uint8_t *dst, const uint8_t *src, int len) +{ + int s = 0, d = 0; + + while (s < len) + { + if (!src[s] && !src[s + 1]) + { + // hit 00 00 xx + dst[d] = dst[d + 1] = 0; + s += 2; + d += 2; + if (src[s] == 3) + { + s++; // 00 00 03 xx --> 00 00 xx + if (s >= len) + return d; + } + } + dst[d++] = src[s++]; + } + + return d; +} + +cBitStream::cBitStream(const uint8_t *buf, const int len) + : data(buf), + count(len), + index(0) +{ +} + +cBitStream::~cBitStream() +{ +} + +int cBitStream::getBit() +{ + if (index >= count) + return (1); // -> no infinite colomb's ... + + int r = (data[index >> 3] >> (7 - (index & 7))) & 1; + ++index; + + return (r); +} + +uint32_t cBitStream::getBits(uint32_t n) +{ + uint32_t r = 0; + + while (n--) + r = (r | (getBit() << n)); + + return (r); +} + +void cBitStream::skipBits(uint32_t n) +{ + index += n; +} + +uint32_t cBitStream::getUeGolomb() +{ + int n = 0; + + while (!getBit() && (n < 32)) + n++; + + return (n ? ((1 << n) - 1) + getBits(n) : 0); +} + +int32_t cBitStream::getSeGolomb() +{ + uint32_t r = getUeGolomb() + 1; + + return ((r & 1) ? -(r >> 1) : (r >> 1)); +} + +void cBitStream::skipGolomb() +{ + int n = 0; + + while (!getBit() && (n < 32)) + n++; + + skipBits(n); +} + +void cBitStream::skipUeGolomb() +{ + skipGolomb(); +} + +void cBitStream::skipSeGolomb() +{ + skipGolomb(); +} + +void cBitStream::byteAlign() +{ + int n = index % 8; + + if (n > 0) + skipBits(8 - n); +} diff --git a/streaminfo.h b/streaminfo.h new file mode 100644 index 0000000..5c74b0c --- /dev/null +++ b/streaminfo.h @@ -0,0 +1,98 @@ +/* + * recv.h: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#ifndef __streaminfo_h_ +#define __streaminfo_h_ + +#include <stdint.h> + +#include "global.h" + +class cMarkAdStreamInfo +{ +private: + // taken from femon + enum + { + NAL_SEI = 0x06, // Supplemental Enhancement Information + NAL_SPS = 0x07, // Sequence Parameter Set + NAL_AUD = 0x09, // Access Unit Delimiter + NAL_END_SEQ = 0x0A // End of Sequence + }; + int nalUnescape(uint8_t *dst, const uint8_t *src, int len); + + void FindH264VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); + void FindH262VideoInfos(MarkAdContext *maContext, uchar *pkt, int len); +public: + void FindVideoInfos(MarkAdContext *maContext, uchar *pkt, int len); + void FindAC3AudioInfos(MarkAdContext *maContext, uchar *espkt, int eslen); + + +}; + +// taken from femon +class cBitStream +{ +private: + const uint8_t *data; + int count; // in bits + int index; // in bits + +public: + cBitStream(const uint8_t *buf, const int len); + ~cBitStream(); + + int getBit(); + uint32_t getBits(uint32_t n); + void skipBits(uint32_t n); + uint32_t getUeGolomb(); + int32_t getSeGolomb(); + void skipGolomb(); + void skipUeGolomb(); + void skipSeGolomb(); + void byteAlign(); + + void skipBit() + { + skipBits(1); + } + uint32_t getU8() + { + return getBits(8); + } + uint32_t getU16() + { + return ((getBits(8) << 8) | getBits(8)); + } + uint32_t getU24() + { + return ((getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); + } + uint32_t getU32() + { + return ((getBits(8) << 24) | (getBits(8) << 16) | (getBits(8) << 8) | getBits(8)); + } + bool isEOF() + { + return (index >= count); + } + void reset() + { + index = 0; + } + int getIndex() + { + return (isEOF() ? count : index); + } + const uint8_t *getData() + { + return (isEOF() ? NULL : data + (index / 8)); + } +}; + +#endif
\ No newline at end of file @@ -8,6 +8,133 @@ #include "video.h" +cMarkAdLogo::cMarkAdLogo(int RecvNumber, MarkAdContext *maContext) +{ + macontext=maContext; + + // 3x3 GX Sobel mask + GX[0][0] = -1; + GX[0][1] = 0; + GX[0][2] = 1; + GX[1][0] = -2; // 2 + GX[1][1] = 0; + GX[1][2] = 2; // 2 + GX[2][0] = -1; + GX[2][1] = 0; + GX[2][2] = 1; + + // 3x3 GY Sobel mask + GY[0][0] = 1; + GY[0][1] = 2; // 2 + GY[0][2] = 1; + GY[1][0] = 0; + GY[1][1] = 0; + GY[1][2] = 0; + GY[2][0] = -1; + GY[2][1] = -2; //2 + GY[2][2] = -1; + + plane=NULL; + first=true; +} + +cMarkAdLogo::~cMarkAdLogo() +{ + if (plane) free(plane); +} + +void cMarkAdLogo::SaveFrame(int LastIFrame) +{ + if (!macontext) return; + if (!macontext->Video.Info.Width) return; + if (!plane) return; + + FILE *pFile; + char szFilename[32]; + + // Open file + sprintf(szFilename, "frame%06d.pgm", LastIFrame); + pFile=fopen(szFilename, "wb"); + if (pFile==NULL) + return; + + // Write header + fprintf(pFile, "P5\n%d %d\n255\n", macontext->Video.Info.Width,LOGOHEIGHT); + + // Write pixel data + fwrite(plane,1,macontext->Video.Info.Width*LOGOHEIGHT,pFile); + // Close file + fclose(pFile); + + dsyslog("markad saved frame %i",LastIFrame); + if (LastIFrame>750) abort(); +} + +int cMarkAdLogo::Process(int LastIFrame) +{ + if (!macontext) return 0; + if (!macontext->Video.Info.Width) return 0; + if (!macontext->Video.Data.Valid) return 0; + + if (!plane) + { + plane=(uchar *) malloc(LOGOHEIGHT*macontext->Video.Info.Width); + if (!plane) return 0; + } + + int SUM; + int sumX,sumY; + + for (int Y=0; Y<=LOGOHEIGHT-1; Y++) + { + for (int X=0; X<=macontext->Video.Info.Width-1; X++) + { + sumX=0; + sumY=0; + + // image boundaries + if (Y==0 || Y==LOGOHEIGHT-1) + SUM=0; + else if (X==0 || X==macontext->Video.Info.Width-1) + SUM=0; + // convolution starts here + else + { + // X Gradient approximation + for (int I=-1; I<=1; I++) + { + for (int J=-1; J<=1; J++) + { + sumX=sumX+ (int) ((*(macontext->Video.Data.Plane[0]+X+I+ + (Y+J)*macontext->Video.Info.Width))*GX[I+1][J+1]); + } + } + + // Y Gradient approximation + for (int I=-1; I<=1; I++) + { + for (int J=-1; J<=1; J++) + { + sumY=sumY+ (int) ((*(macontext->Video.Data.Plane[0]+X+I+ + (Y+J)*macontext->Video.Info.Width))*GY[I+1][J+1]); + } + } + + // Gradient Magnitude approximation + SUM = abs(sumX) + abs(sumY); + } + + if (SUM>=127) SUM=255; + if (SUM<127) SUM=0; + + plane[X+Y*macontext->Video.Info.Width]=255-(uchar) (SUM); + } + } + //SaveFrame(LastIFrame); + + return 0; +} + cMarkAdBlackBordersHoriz::cMarkAdBlackBordersHoriz(int RecvNumber, MarkAdContext *maContext) { macontext=maContext; @@ -50,7 +177,7 @@ int cMarkAdBlackBordersHoriz::Process(int LastIFrame, int *BorderIFrame) #define BRIGHTNESS 20 if (!macontext) return 0; if (!macontext->Video.Data.Valid) return 0; -return 0; + return 0; *BorderIFrame=borderiframe; @@ -160,12 +287,14 @@ cMarkAdVideo::cMarkAdVideo(int RecvNumber,MarkAdContext *maContext) mark.Position=0; hborder=new cMarkAdBlackBordersHoriz(RecvNumber,maContext); + logo = new cMarkAdLogo(RecvNumber,maContext); } cMarkAdVideo::~cMarkAdVideo() { ResetMark(); - delete hborder; + if (hborder) delete hborder; + if (logo) delete logo; } void cMarkAdVideo::ResetMark() @@ -215,6 +344,8 @@ MarkAdMark *cMarkAdVideo::Process(int LastIFrame) ResetMark(); if (!LastIFrame) return NULL; + logo->Process(LastIFrame); + if (macontext->State.ContentStarted) { int borderiframe; @@ -247,9 +378,9 @@ MarkAdMark *cMarkAdVideo::Process(int LastIFrame) { char *buf=NULL; if (asprintf(&buf,"aspect ratio change from %i:%i to %i:%i (%i)", - aspectratio.Num,aspectratio.Den, - macontext->Video.Info.AspectRatio.Num, - macontext->Video.Info.AspectRatio.Den,LastIFrame)!=-1) + aspectratio.Num,aspectratio.Den, + macontext->Video.Info.AspectRatio.Num, + macontext->Video.Info.AspectRatio.Den,LastIFrame)!=-1) { isyslog("markad [%i]: %s",recvnumber, buf); AddMark(LastIFrame,buf); @@ -12,10 +12,31 @@ #include <vdr/tools.h> // needed for (d/e/i)syslog #include <time.h> + +#if 1 #include <stdio.h> +#endif + +#include <math.h> #include "global.h" +class cMarkAdLogo +{ +private: +#define LOGOHEIGHT 100 + int GX[3][3]; + int GY[3][3]; + uchar *plane; + bool first; + MarkAdContext *macontext; +public: + cMarkAdLogo(int RecvNumber, MarkAdContext *maContext); + ~cMarkAdLogo(); + void SaveFrame(int LastIFrame); + int Process(int LastIFrame); +}; + class cMarkAdBlackBordersHoriz { private: @@ -38,6 +59,7 @@ private: MarkAdAspectRatio aspectratio; cMarkAdBlackBordersHoriz *hborder; + cMarkAdLogo *logo; void ResetMark(); bool AddMark(int Position, const char *Comment); |