summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile18
-rw-r--r--decoder.cpp863
-rw-r--r--decoder.h78
-rw-r--r--markad-standalone.cpp36
-rw-r--r--recv.cpp86
-rw-r--r--recv.h5
-rw-r--r--streaminfo.cpp827
-rw-r--r--streaminfo.h98
-rw-r--r--video.cpp141
-rw-r--r--video.h22
10 files changed, 1137 insertions, 1037 deletions
diff --git a/Makefile b/Makefile
index 143985b..5b664d1 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
}
diff --git a/decoder.h b/decoder.h
index 2006781..c1e7f53 100644
--- a/decoder.h
+++ b/decoder.h
@@ -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;
}
diff --git a/recv.cpp b/recv.cpp
index 7ed56aa..b2e26f0 100644
--- a/recv.cpp
+++ b/recv.cpp
@@ -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;
diff --git a/recv.h b/recv.h
index 8060a21..5920f6f 100644
--- a/recv.h
+++ b/recv.h
@@ -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
diff --git a/video.cpp b/video.cpp
index ad52153..858b49f 100644
--- a/video.cpp
+++ b/video.cpp
@@ -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);
diff --git a/video.h b/video.h
index 56b8f33..ecc6d74 100644
--- a/video.h
+++ b/video.h
@@ -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);