From 3f73024a9bf0a0a722b8e49842ddd136609894b6 Mon Sep 17 00:00:00 2001 From: xzl Date: Sat, 1 Apr 2017 16:35:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes .cproject | 279 ++++++ .gitignore | 1 + .project | 27 + .settings/language.settings.xml | 36 + ARM/makefile | 70 ++ ARM/objects.mk | 8 + ARM/sources.mk | 38 + ARM/src/Codec/subdir.mk | 27 + ARM/src/Device/subdir.mk | 30 + ARM/src/H264/subdir.mk | 50 + ARM/src/Http/subdir.mk | 27 + ARM/src/MedaiFile/CRC/subdir.mk | 24 + ARM/src/MedaiFile/subdir.mk | 36 + ARM/src/Player/subdir.mk | 30 + ARM/src/RTP/subdir.mk | 27 + ARM/src/Rtmp/subdir.mk | 51 ++ ARM/src/Rtsp/subdir.mk | 48 + ARM/src/Shell/subdir.mk | 27 + ARM/src/subdir.mk | 24 + X64/makefile | 70 ++ X64/objects.mk | 8 + X64/sources.mk | 38 + X64/src/Codec/subdir.mk | 27 + X64/src/Device/subdir.mk | 30 + X64/src/H264/subdir.mk | 50 + X64/src/Http/subdir.mk | 27 + X64/src/MedaiFile/CRC/subdir.mk | 24 + X64/src/MedaiFile/subdir.mk | 36 + X64/src/Player/subdir.mk | 30 + X64/src/RTP/subdir.mk | 27 + X64/src/Rtmp/subdir.mk | 51 ++ X64/src/Rtsp/subdir.mk | 48 + X64/src/Shell/subdir.mk | 27 + X64/src/subdir.mk | 24 + src/Codec/AACEncoder.cpp | 110 +++ src/Codec/AACEncoder.h | 38 + src/Codec/H264Encoder.cpp | 349 +++++++ src/Codec/H264Encoder.h | 48 + src/Device/Device.cpp | 256 ++++++ src/Device/Device.h | 108 +++ src/Device/PlayerProxy.cpp | 153 ++++ src/Device/PlayerProxy.h | 48 + src/Device/base64.cpp | 167 ++++ src/Device/base64.h | 55 ++ src/H264/H264Parser.cpp | 100 ++ src/H264/H264Parser.h | 56 ++ src/H264/SPSParser.c | 1039 +++++++++++++++++++++ src/H264/SPSParser.h | 192 ++++ src/H264/h264_bit_reader.cpp | 121 +++ src/H264/h264_bit_reader.h | 81 ++ src/H264/h264_parser.cpp | 1372 ++++++++++++++++++++++++++++ src/H264/h264_parser.h | 491 ++++++++++ src/H264/h264_poc.cpp | 232 +++++ src/H264/h264_poc.h | 45 + src/H264/macros.h | 100 ++ src/H264/ranges.cpp | 9 + src/H264/ranges.h | 154 ++++ src/Http/HttpSession.cpp | 410 +++++++++ src/Http/HttpSession.h | 51 ++ src/Http/strCoding.cpp | 72 ++ src/Http/strCoding.h | 37 + src/MedaiFile/CRC/crc32.cpp | 97 ++ src/MedaiFile/CRC/crc32.h | 16 + src/MedaiFile/HLSMaker.cpp | 159 ++++ src/MedaiFile/HLSMaker.h | 62 ++ src/MedaiFile/MediaReader.cpp | 349 +++++++ src/MedaiFile/MediaReader.h | 85 ++ src/MedaiFile/MediaRecorder.cpp | 62 ++ src/MedaiFile/MediaRecorder.h | 50 + src/MedaiFile/Mp4Maker.cpp | 190 ++++ src/MedaiFile/Mp4Maker.h | 82 ++ src/MedaiFile/TSMaker.cpp | 585 ++++++++++++ src/MedaiFile/TSMaker.h | 249 +++++ src/MediaSender.h | 24 + src/Player/MediaPlayer.cpp | 57 ++ src/Player/MediaPlayer.h | 39 + src/Player/Player.cpp | 118 +++ src/Player/Player.h | 53 ++ src/Player/PlayerBase.cpp | 34 + src/Player/PlayerBase.h | 219 +++++ src/RTP/RtpMaker.h | 85 ++ src/RTP/RtpMakerAAC.cpp | 81 ++ src/RTP/RtpMakerAAC.h | 42 + src/RTP/RtpMakerH264.cpp | 98 ++ src/RTP/RtpMakerH264.h | 42 + src/Rtmp/Rtmp.h | 223 +++++ src/Rtmp/RtmpMediaSource.cpp | 42 + src/Rtmp/RtmpMediaSource.h | 163 ++++ src/Rtmp/RtmpParser.cpp | 231 +++++ src/Rtmp/RtmpParser.h | 130 +++ src/Rtmp/RtmpPlayer.cpp | 326 +++++++ src/Rtmp/RtmpPlayer.h | 143 +++ src/Rtmp/RtmpPlayerImp.cpp | 23 + src/Rtmp/RtmpPlayerImp.h | 62 ++ src/Rtmp/RtmpProtocol.cpp | 435 +++++++++ src/Rtmp/RtmpProtocol.h | 93 ++ src/Rtmp/RtmpPusher.cpp | 260 ++++++ src/Rtmp/RtmpPusher.h | 95 ++ src/Rtmp/RtmpSession.cpp | 316 +++++++ src/Rtmp/RtmpSession.h | 79 ++ src/Rtmp/RtmpToRtspMediaSource.cpp | 150 +++ src/Rtmp/RtmpToRtspMediaSource.h | 96 ++ src/Rtmp/amf.cpp | 528 +++++++++++ src/Rtmp/amf.h | 223 +++++ src/Rtmp/utils.cpp | 64 ++ src/Rtmp/utils.h | 17 + src/Rtsp/RtpBroadCaster.cpp | 153 ++++ src/Rtsp/RtpBroadCaster.h | 81 ++ src/Rtsp/RtpParser.cpp | 273 ++++++ src/Rtsp/RtpParser.h | 131 +++ src/Rtsp/Rtsp.cpp | 98 ++ src/Rtsp/Rtsp.h | 158 ++++ src/Rtsp/RtspMediaSource.cpp | 42 + src/Rtsp/RtspMediaSource.h | 163 ++++ src/Rtsp/RtspPlayer.cpp | 655 +++++++++++++ src/Rtsp/RtspPlayer.h | 159 ++++ src/Rtsp/RtspPlayerImp.cpp | 23 + src/Rtsp/RtspPlayerImp.h | 65 ++ src/Rtsp/RtspSession.cpp | 766 ++++++++++++++++ src/Rtsp/RtspSession.h | 143 +++ src/Rtsp/RtspToRtmpMediaSource.cpp | 213 +++++ src/Rtsp/RtspToRtmpMediaSource.h | 102 +++ src/Rtsp/UDPServer.cpp | 94 ++ src/Rtsp/UDPServer.h | 51 ++ src/Shell/CMD.cpp | 88 ++ src/Shell/CMD.h | 246 +++++ src/Shell/ShellSession.cpp | 171 ++++ src/Shell/ShellSession.h | 62 ++ src/config.cpp | 279 ++++++ src/config.h | 152 +++ 131 files changed, 18216 insertions(+) create mode 100644 .DS_Store create mode 100644 .cproject create mode 100644 .project create mode 100644 .settings/language.settings.xml create mode 100644 ARM/makefile create mode 100644 ARM/objects.mk create mode 100644 ARM/sources.mk create mode 100644 ARM/src/Codec/subdir.mk create mode 100644 ARM/src/Device/subdir.mk create mode 100644 ARM/src/H264/subdir.mk create mode 100644 ARM/src/Http/subdir.mk create mode 100644 ARM/src/MedaiFile/CRC/subdir.mk create mode 100644 ARM/src/MedaiFile/subdir.mk create mode 100644 ARM/src/Player/subdir.mk create mode 100644 ARM/src/RTP/subdir.mk create mode 100644 ARM/src/Rtmp/subdir.mk create mode 100644 ARM/src/Rtsp/subdir.mk create mode 100644 ARM/src/Shell/subdir.mk create mode 100644 ARM/src/subdir.mk create mode 100644 X64/makefile create mode 100644 X64/objects.mk create mode 100644 X64/sources.mk create mode 100644 X64/src/Codec/subdir.mk create mode 100644 X64/src/Device/subdir.mk create mode 100644 X64/src/H264/subdir.mk create mode 100644 X64/src/Http/subdir.mk create mode 100644 X64/src/MedaiFile/CRC/subdir.mk create mode 100644 X64/src/MedaiFile/subdir.mk create mode 100644 X64/src/Player/subdir.mk create mode 100644 X64/src/RTP/subdir.mk create mode 100644 X64/src/Rtmp/subdir.mk create mode 100644 X64/src/Rtsp/subdir.mk create mode 100644 X64/src/Shell/subdir.mk create mode 100644 X64/src/subdir.mk create mode 100644 src/Codec/AACEncoder.cpp create mode 100644 src/Codec/AACEncoder.h create mode 100644 src/Codec/H264Encoder.cpp create mode 100644 src/Codec/H264Encoder.h create mode 100644 src/Device/Device.cpp create mode 100644 src/Device/Device.h create mode 100644 src/Device/PlayerProxy.cpp create mode 100644 src/Device/PlayerProxy.h create mode 100644 src/Device/base64.cpp create mode 100644 src/Device/base64.h create mode 100644 src/H264/H264Parser.cpp create mode 100644 src/H264/H264Parser.h create mode 100644 src/H264/SPSParser.c create mode 100644 src/H264/SPSParser.h create mode 100644 src/H264/h264_bit_reader.cpp create mode 100644 src/H264/h264_bit_reader.h create mode 100644 src/H264/h264_parser.cpp create mode 100644 src/H264/h264_parser.h create mode 100644 src/H264/h264_poc.cpp create mode 100644 src/H264/h264_poc.h create mode 100644 src/H264/macros.h create mode 100644 src/H264/ranges.cpp create mode 100644 src/H264/ranges.h create mode 100644 src/Http/HttpSession.cpp create mode 100644 src/Http/HttpSession.h create mode 100644 src/Http/strCoding.cpp create mode 100644 src/Http/strCoding.h create mode 100644 src/MedaiFile/CRC/crc32.cpp create mode 100644 src/MedaiFile/CRC/crc32.h create mode 100644 src/MedaiFile/HLSMaker.cpp create mode 100644 src/MedaiFile/HLSMaker.h create mode 100644 src/MedaiFile/MediaReader.cpp create mode 100644 src/MedaiFile/MediaReader.h create mode 100644 src/MedaiFile/MediaRecorder.cpp create mode 100644 src/MedaiFile/MediaRecorder.h create mode 100644 src/MedaiFile/Mp4Maker.cpp create mode 100644 src/MedaiFile/Mp4Maker.h create mode 100644 src/MedaiFile/TSMaker.cpp create mode 100644 src/MedaiFile/TSMaker.h create mode 100644 src/MediaSender.h create mode 100644 src/Player/MediaPlayer.cpp create mode 100644 src/Player/MediaPlayer.h create mode 100644 src/Player/Player.cpp create mode 100644 src/Player/Player.h create mode 100644 src/Player/PlayerBase.cpp create mode 100644 src/Player/PlayerBase.h create mode 100644 src/RTP/RtpMaker.h create mode 100644 src/RTP/RtpMakerAAC.cpp create mode 100644 src/RTP/RtpMakerAAC.h create mode 100644 src/RTP/RtpMakerH264.cpp create mode 100644 src/RTP/RtpMakerH264.h create mode 100644 src/Rtmp/Rtmp.h create mode 100644 src/Rtmp/RtmpMediaSource.cpp create mode 100644 src/Rtmp/RtmpMediaSource.h create mode 100644 src/Rtmp/RtmpParser.cpp create mode 100644 src/Rtmp/RtmpParser.h create mode 100644 src/Rtmp/RtmpPlayer.cpp create mode 100644 src/Rtmp/RtmpPlayer.h create mode 100644 src/Rtmp/RtmpPlayerImp.cpp create mode 100644 src/Rtmp/RtmpPlayerImp.h create mode 100644 src/Rtmp/RtmpProtocol.cpp create mode 100644 src/Rtmp/RtmpProtocol.h create mode 100644 src/Rtmp/RtmpPusher.cpp create mode 100644 src/Rtmp/RtmpPusher.h create mode 100644 src/Rtmp/RtmpSession.cpp create mode 100644 src/Rtmp/RtmpSession.h create mode 100644 src/Rtmp/RtmpToRtspMediaSource.cpp create mode 100644 src/Rtmp/RtmpToRtspMediaSource.h create mode 100644 src/Rtmp/amf.cpp create mode 100644 src/Rtmp/amf.h create mode 100644 src/Rtmp/utils.cpp create mode 100644 src/Rtmp/utils.h create mode 100644 src/Rtsp/RtpBroadCaster.cpp create mode 100644 src/Rtsp/RtpBroadCaster.h create mode 100644 src/Rtsp/RtpParser.cpp create mode 100644 src/Rtsp/RtpParser.h create mode 100644 src/Rtsp/Rtsp.cpp create mode 100644 src/Rtsp/Rtsp.h create mode 100644 src/Rtsp/RtspMediaSource.cpp create mode 100644 src/Rtsp/RtspMediaSource.h create mode 100644 src/Rtsp/RtspPlayer.cpp create mode 100644 src/Rtsp/RtspPlayer.h create mode 100644 src/Rtsp/RtspPlayerImp.cpp create mode 100644 src/Rtsp/RtspPlayerImp.h create mode 100644 src/Rtsp/RtspSession.cpp create mode 100644 src/Rtsp/RtspSession.h create mode 100644 src/Rtsp/RtspToRtmpMediaSource.cpp create mode 100644 src/Rtsp/RtspToRtmpMediaSource.h create mode 100644 src/Rtsp/UDPServer.cpp create mode 100644 src/Rtsp/UDPServer.h create mode 100644 src/Shell/CMD.cpp create mode 100644 src/Shell/CMD.h create mode 100644 src/Shell/ShellSession.cpp create mode 100644 src/Shell/ShellSession.h create mode 100644 src/config.cpp create mode 100644 src/config.h diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..93a78cb22a11fe3a850e5d09feea009a62200f1b GIT binary patch literal 6148 zcmeHKu};HK476#7N-P~2-^j|$5>;hj<_A#HF;XNd_H2AM+}Q>ZrHG9Ioh84EpM5XN z4e_&?`Qi0+XSO%99h_)yT-L@sePvg*Lv)@o4gEOvh~l_a{iO|ZH+Hrc8y?36{~np! z_pl&V)#*Hp{WOi24%40#kOERb3P=Gd@T&so*|gntqE;y&1*E{20{lNTII%076XVx` zh1YlHw?rDAE`ifoKtW1nozt(4{uR! z-X&_40#ab9z$U{z`~L&{hxva=QX~bWz`s(!x5uaB0iRU8b@g%VwGI9Z|1{J_IhJU} jz-Yw?*otqy)ipjN-xbb@LC1d3fw~A#7nv0J3k5y^FI61P literal 0 HcmV?d00001 diff --git a/.cproject b/.cproject new file mode 100644 index 00000000..4285f08a --- /dev/null +++ b/.cproject @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index 4581ef2e..a72cde77 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ *.exe *.out *.app +/X64/ diff --git a/.project b/.project new file mode 100644 index 00000000..c32f761c --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + ZLMediaKit + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 00000000..655295cc --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ARM/makefile b/ARM/makefile new file mode 100644 index 00000000..7482988c --- /dev/null +++ b/ARM/makefile @@ -0,0 +1,70 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf + +# All of the sources participating in the build are defined here +-include sources.mk +-include src/Shell/subdir.mk +-include src/Rtsp/subdir.mk +-include src/Rtmp/subdir.mk +-include src/RTP/subdir.mk +-include src/Player/subdir.mk +-include src/MedaiFile/CRC/subdir.mk +-include src/MedaiFile/subdir.mk +-include src/Http/subdir.mk +-include src/H264/subdir.mk +-include src/Device/subdir.mk +-include src/Codec/subdir.mk +-include src/subdir.mk +-include subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(CC_DEPS)),) +-include $(CC_DEPS) +endif +ifneq ($(strip $(C++_DEPS)),) +-include $(C++_DEPS) +endif +ifneq ($(strip $(C_UPPER_DEPS)),) +-include $(C_UPPER_DEPS) +endif +ifneq ($(strip $(CXX_DEPS)),) +-include $(CXX_DEPS) +endif +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +ifneq ($(strip $(CPP_DEPS)),) +-include $(CPP_DEPS) +endif +endif + +-include ../makefile.defs + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: libZLMediaKit.a + +# Tool invocations +libZLMediaKit.a: $(OBJS) $(USER_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: Cross GCC Archiver' + arm-linux-gnueabi-ar -r "libZLMediaKit.a" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +clean: + -$(RM) $(CC_DEPS)$(C++_DEPS)$(OBJS)$(C_UPPER_DEPS)$(CXX_DEPS)$(ARCHIVES)$(C_DEPS)$(CPP_DEPS) libZLMediaKit.a + -@echo ' ' + +.PHONY: all clean dependents +.SECONDARY: + +-include ../makefile.targets diff --git a/ARM/objects.mk b/ARM/objects.mk new file mode 100644 index 00000000..742c2da0 --- /dev/null +++ b/ARM/objects.mk @@ -0,0 +1,8 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +USER_OBJS := + +LIBS := + diff --git a/ARM/sources.mk b/ARM/sources.mk new file mode 100644 index 00000000..f39f631c --- /dev/null +++ b/ARM/sources.mk @@ -0,0 +1,38 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +C_UPPER_SRCS := +CXX_SRCS := +C++_SRCS := +OBJ_SRCS := +CC_SRCS := +ASM_SRCS := +C_SRCS := +CPP_SRCS := +O_SRCS := +S_UPPER_SRCS := +CC_DEPS := +C++_DEPS := +OBJS := +C_UPPER_DEPS := +CXX_DEPS := +ARCHIVES := +C_DEPS := +CPP_DEPS := + +# Every subdirectory with source files must be described here +SUBDIRS := \ +src/Codec \ +src/Device \ +src/H264 \ +src/Http \ +src/MedaiFile/CRC \ +src/MedaiFile \ +src/Player \ +src/RTP \ +src/Rtmp \ +src/Rtsp \ +src/Shell \ +src \ + diff --git a/ARM/src/Codec/subdir.mk b/ARM/src/Codec/subdir.mk new file mode 100644 index 00000000..1093c63b --- /dev/null +++ b/ARM/src/Codec/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Codec/AACEncoder.cpp \ +../src/Codec/H264Encoder.cpp + +OBJS += \ +./src/Codec/AACEncoder.o \ +./src/Codec/H264Encoder.o + +CPP_DEPS += \ +./src/Codec/AACEncoder.d \ +./src/Codec/H264Encoder.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Codec/%.o: ../src/Codec/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Device/subdir.mk b/ARM/src/Device/subdir.mk new file mode 100644 index 00000000..e7934241 --- /dev/null +++ b/ARM/src/Device/subdir.mk @@ -0,0 +1,30 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Device/Device.cpp \ +../src/Device/PlayerProxy.cpp \ +../src/Device/base64.cpp + +OBJS += \ +./src/Device/Device.o \ +./src/Device/PlayerProxy.o \ +./src/Device/base64.o + +CPP_DEPS += \ +./src/Device/Device.d \ +./src/Device/PlayerProxy.d \ +./src/Device/base64.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Device/%.o: ../src/Device/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/H264/subdir.mk b/ARM/src/H264/subdir.mk new file mode 100644 index 00000000..b286a530 --- /dev/null +++ b/ARM/src/H264/subdir.mk @@ -0,0 +1,50 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/H264/SPSParser.c + +CPP_SRCS += \ +../src/H264/H264Parser.cpp \ +../src/H264/h264_bit_reader.cpp \ +../src/H264/h264_parser.cpp \ +../src/H264/h264_poc.cpp \ +../src/H264/ranges.cpp + +OBJS += \ +./src/H264/H264Parser.o \ +./src/H264/SPSParser.o \ +./src/H264/h264_bit_reader.o \ +./src/H264/h264_parser.o \ +./src/H264/h264_poc.o \ +./src/H264/ranges.o + +C_DEPS += \ +./src/H264/SPSParser.d + +CPP_DEPS += \ +./src/H264/H264Parser.d \ +./src/H264/h264_bit_reader.d \ +./src/H264/h264_parser.d \ +./src/H264/h264_poc.d \ +./src/H264/ranges.d + + +# Each subdirectory must supply rules for building sources it contributes +src/H264/%.o: ../src/H264/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + +src/H264/%.o: ../src/H264/%.c + @echo 'Building file: $<' + @echo 'Invoking: Cross GCC Compiler' + arm-linux-gnueabi-gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Http/subdir.mk b/ARM/src/Http/subdir.mk new file mode 100644 index 00000000..2cb9c1f1 --- /dev/null +++ b/ARM/src/Http/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Http/HttpSession.cpp \ +../src/Http/strCoding.cpp + +OBJS += \ +./src/Http/HttpSession.o \ +./src/Http/strCoding.o + +CPP_DEPS += \ +./src/Http/HttpSession.d \ +./src/Http/strCoding.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Http/%.o: ../src/Http/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/MedaiFile/CRC/subdir.mk b/ARM/src/MedaiFile/CRC/subdir.mk new file mode 100644 index 00000000..42ac7a27 --- /dev/null +++ b/ARM/src/MedaiFile/CRC/subdir.mk @@ -0,0 +1,24 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/MedaiFile/CRC/crc32.cpp + +OBJS += \ +./src/MedaiFile/CRC/crc32.o + +CPP_DEPS += \ +./src/MedaiFile/CRC/crc32.d + + +# Each subdirectory must supply rules for building sources it contributes +src/MedaiFile/CRC/%.o: ../src/MedaiFile/CRC/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/MedaiFile/subdir.mk b/ARM/src/MedaiFile/subdir.mk new file mode 100644 index 00000000..f3444009 --- /dev/null +++ b/ARM/src/MedaiFile/subdir.mk @@ -0,0 +1,36 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/MedaiFile/HLSMaker.cpp \ +../src/MedaiFile/MediaReader.cpp \ +../src/MedaiFile/MediaRecorder.cpp \ +../src/MedaiFile/Mp4Maker.cpp \ +../src/MedaiFile/TSMaker.cpp + +OBJS += \ +./src/MedaiFile/HLSMaker.o \ +./src/MedaiFile/MediaReader.o \ +./src/MedaiFile/MediaRecorder.o \ +./src/MedaiFile/Mp4Maker.o \ +./src/MedaiFile/TSMaker.o + +CPP_DEPS += \ +./src/MedaiFile/HLSMaker.d \ +./src/MedaiFile/MediaReader.d \ +./src/MedaiFile/MediaRecorder.d \ +./src/MedaiFile/Mp4Maker.d \ +./src/MedaiFile/TSMaker.d + + +# Each subdirectory must supply rules for building sources it contributes +src/MedaiFile/%.o: ../src/MedaiFile/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Player/subdir.mk b/ARM/src/Player/subdir.mk new file mode 100644 index 00000000..13259d09 --- /dev/null +++ b/ARM/src/Player/subdir.mk @@ -0,0 +1,30 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Player/MediaPlayer.cpp \ +../src/Player/Player.cpp \ +../src/Player/PlayerBase.cpp + +OBJS += \ +./src/Player/MediaPlayer.o \ +./src/Player/Player.o \ +./src/Player/PlayerBase.o + +CPP_DEPS += \ +./src/Player/MediaPlayer.d \ +./src/Player/Player.d \ +./src/Player/PlayerBase.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Player/%.o: ../src/Player/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/RTP/subdir.mk b/ARM/src/RTP/subdir.mk new file mode 100644 index 00000000..38f2e6e4 --- /dev/null +++ b/ARM/src/RTP/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/RTP/RtpMakerAAC.cpp \ +../src/RTP/RtpMakerH264.cpp + +OBJS += \ +./src/RTP/RtpMakerAAC.o \ +./src/RTP/RtpMakerH264.o + +CPP_DEPS += \ +./src/RTP/RtpMakerAAC.d \ +./src/RTP/RtpMakerH264.d + + +# Each subdirectory must supply rules for building sources it contributes +src/RTP/%.o: ../src/RTP/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Rtmp/subdir.mk b/ARM/src/Rtmp/subdir.mk new file mode 100644 index 00000000..33492ab6 --- /dev/null +++ b/ARM/src/Rtmp/subdir.mk @@ -0,0 +1,51 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Rtmp/RtmpMediaSource.cpp \ +../src/Rtmp/RtmpParser.cpp \ +../src/Rtmp/RtmpPlayer.cpp \ +../src/Rtmp/RtmpPlayerImp.cpp \ +../src/Rtmp/RtmpProtocol.cpp \ +../src/Rtmp/RtmpPusher.cpp \ +../src/Rtmp/RtmpSession.cpp \ +../src/Rtmp/RtmpToRtspMediaSource.cpp \ +../src/Rtmp/amf.cpp \ +../src/Rtmp/utils.cpp + +OBJS += \ +./src/Rtmp/RtmpMediaSource.o \ +./src/Rtmp/RtmpParser.o \ +./src/Rtmp/RtmpPlayer.o \ +./src/Rtmp/RtmpPlayerImp.o \ +./src/Rtmp/RtmpProtocol.o \ +./src/Rtmp/RtmpPusher.o \ +./src/Rtmp/RtmpSession.o \ +./src/Rtmp/RtmpToRtspMediaSource.o \ +./src/Rtmp/amf.o \ +./src/Rtmp/utils.o + +CPP_DEPS += \ +./src/Rtmp/RtmpMediaSource.d \ +./src/Rtmp/RtmpParser.d \ +./src/Rtmp/RtmpPlayer.d \ +./src/Rtmp/RtmpPlayerImp.d \ +./src/Rtmp/RtmpProtocol.d \ +./src/Rtmp/RtmpPusher.d \ +./src/Rtmp/RtmpSession.d \ +./src/Rtmp/RtmpToRtspMediaSource.d \ +./src/Rtmp/amf.d \ +./src/Rtmp/utils.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Rtmp/%.o: ../src/Rtmp/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Rtsp/subdir.mk b/ARM/src/Rtsp/subdir.mk new file mode 100644 index 00000000..00ff592d --- /dev/null +++ b/ARM/src/Rtsp/subdir.mk @@ -0,0 +1,48 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Rtsp/RtpBroadCaster.cpp \ +../src/Rtsp/RtpParser.cpp \ +../src/Rtsp/Rtsp.cpp \ +../src/Rtsp/RtspMediaSource.cpp \ +../src/Rtsp/RtspPlayer.cpp \ +../src/Rtsp/RtspPlayerImp.cpp \ +../src/Rtsp/RtspSession.cpp \ +../src/Rtsp/RtspToRtmpMediaSource.cpp \ +../src/Rtsp/UDPServer.cpp + +OBJS += \ +./src/Rtsp/RtpBroadCaster.o \ +./src/Rtsp/RtpParser.o \ +./src/Rtsp/Rtsp.o \ +./src/Rtsp/RtspMediaSource.o \ +./src/Rtsp/RtspPlayer.o \ +./src/Rtsp/RtspPlayerImp.o \ +./src/Rtsp/RtspSession.o \ +./src/Rtsp/RtspToRtmpMediaSource.o \ +./src/Rtsp/UDPServer.o + +CPP_DEPS += \ +./src/Rtsp/RtpBroadCaster.d \ +./src/Rtsp/RtpParser.d \ +./src/Rtsp/Rtsp.d \ +./src/Rtsp/RtspMediaSource.d \ +./src/Rtsp/RtspPlayer.d \ +./src/Rtsp/RtspPlayerImp.d \ +./src/Rtsp/RtspSession.d \ +./src/Rtsp/RtspToRtmpMediaSource.d \ +./src/Rtsp/UDPServer.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Rtsp/%.o: ../src/Rtsp/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/Shell/subdir.mk b/ARM/src/Shell/subdir.mk new file mode 100644 index 00000000..8c2e36e5 --- /dev/null +++ b/ARM/src/Shell/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Shell/CMD.cpp \ +../src/Shell/ShellSession.cpp + +OBJS += \ +./src/Shell/CMD.o \ +./src/Shell/ShellSession.o + +CPP_DEPS += \ +./src/Shell/CMD.d \ +./src/Shell/ShellSession.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Shell/%.o: ../src/Shell/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/ARM/src/subdir.mk b/ARM/src/subdir.mk new file mode 100644 index 00000000..fa6670c5 --- /dev/null +++ b/ARM/src/subdir.mk @@ -0,0 +1,24 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/config.cpp + +OBJS += \ +./src/config.o + +CPP_DEPS += \ +./src/config.d + + +# Each subdirectory must supply rules for building sources it contributes +src/%.o: ../src/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + arm-linux-gnueabi-g++ -std=c++1y -I/home/xzl/soft -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/makefile b/X64/makefile new file mode 100644 index 00000000..37e81e9d --- /dev/null +++ b/X64/makefile @@ -0,0 +1,70 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +-include ../makefile.init + +RM := rm -rf + +# All of the sources participating in the build are defined here +-include sources.mk +-include src/Shell/subdir.mk +-include src/Rtsp/subdir.mk +-include src/Rtmp/subdir.mk +-include src/RTP/subdir.mk +-include src/Player/subdir.mk +-include src/MedaiFile/CRC/subdir.mk +-include src/MedaiFile/subdir.mk +-include src/Http/subdir.mk +-include src/H264/subdir.mk +-include src/Device/subdir.mk +-include src/Codec/subdir.mk +-include src/subdir.mk +-include subdir.mk +-include objects.mk + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(strip $(CC_DEPS)),) +-include $(CC_DEPS) +endif +ifneq ($(strip $(C++_DEPS)),) +-include $(C++_DEPS) +endif +ifneq ($(strip $(C_UPPER_DEPS)),) +-include $(C_UPPER_DEPS) +endif +ifneq ($(strip $(CXX_DEPS)),) +-include $(CXX_DEPS) +endif +ifneq ($(strip $(C_DEPS)),) +-include $(C_DEPS) +endif +ifneq ($(strip $(CPP_DEPS)),) +-include $(CPP_DEPS) +endif +endif + +-include ../makefile.defs + +# Add inputs and outputs from these tool invocations to the build variables + +# All Target +all: libZLMediaKit.so + +# Tool invocations +libZLMediaKit.so: $(OBJS) $(USER_OBJS) + @echo 'Building target: $@' + @echo 'Invoking: Cross G++ Linker' + g++ -shared -o "libZLMediaKit.so" $(OBJS) $(USER_OBJS) $(LIBS) + @echo 'Finished building target: $@' + @echo ' ' + +# Other Targets +clean: + -$(RM) $(LIBRARIES)$(CC_DEPS)$(C++_DEPS)$(OBJS)$(C_UPPER_DEPS)$(CXX_DEPS)$(C_DEPS)$(CPP_DEPS) libZLMediaKit.so + -@echo ' ' + +.PHONY: all clean dependents +.SECONDARY: + +-include ../makefile.targets diff --git a/X64/objects.mk b/X64/objects.mk new file mode 100644 index 00000000..742c2da0 --- /dev/null +++ b/X64/objects.mk @@ -0,0 +1,8 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +USER_OBJS := + +LIBS := + diff --git a/X64/sources.mk b/X64/sources.mk new file mode 100644 index 00000000..db0ac7c5 --- /dev/null +++ b/X64/sources.mk @@ -0,0 +1,38 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +C_UPPER_SRCS := +CXX_SRCS := +C++_SRCS := +OBJ_SRCS := +CC_SRCS := +ASM_SRCS := +C_SRCS := +CPP_SRCS := +O_SRCS := +S_UPPER_SRCS := +LIBRARIES := +CC_DEPS := +C++_DEPS := +OBJS := +C_UPPER_DEPS := +CXX_DEPS := +C_DEPS := +CPP_DEPS := + +# Every subdirectory with source files must be described here +SUBDIRS := \ +src/Codec \ +src/Device \ +src/H264 \ +src/Http \ +src/MedaiFile/CRC \ +src/MedaiFile \ +src/Player \ +src/RTP \ +src/Rtmp \ +src/Rtsp \ +src/Shell \ +src \ + diff --git a/X64/src/Codec/subdir.mk b/X64/src/Codec/subdir.mk new file mode 100644 index 00000000..1054702b --- /dev/null +++ b/X64/src/Codec/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Codec/AACEncoder.cpp \ +../src/Codec/H264Encoder.cpp + +OBJS += \ +./src/Codec/AACEncoder.o \ +./src/Codec/H264Encoder.o + +CPP_DEPS += \ +./src/Codec/AACEncoder.d \ +./src/Codec/H264Encoder.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Codec/%.o: ../src/Codec/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Device/subdir.mk b/X64/src/Device/subdir.mk new file mode 100644 index 00000000..025e229e --- /dev/null +++ b/X64/src/Device/subdir.mk @@ -0,0 +1,30 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Device/Device.cpp \ +../src/Device/PlayerProxy.cpp \ +../src/Device/base64.cpp + +OBJS += \ +./src/Device/Device.o \ +./src/Device/PlayerProxy.o \ +./src/Device/base64.o + +CPP_DEPS += \ +./src/Device/Device.d \ +./src/Device/PlayerProxy.d \ +./src/Device/base64.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Device/%.o: ../src/Device/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/H264/subdir.mk b/X64/src/H264/subdir.mk new file mode 100644 index 00000000..1686a0d1 --- /dev/null +++ b/X64/src/H264/subdir.mk @@ -0,0 +1,50 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +C_SRCS += \ +../src/H264/SPSParser.c + +CPP_SRCS += \ +../src/H264/H264Parser.cpp \ +../src/H264/h264_bit_reader.cpp \ +../src/H264/h264_parser.cpp \ +../src/H264/h264_poc.cpp \ +../src/H264/ranges.cpp + +OBJS += \ +./src/H264/H264Parser.o \ +./src/H264/SPSParser.o \ +./src/H264/h264_bit_reader.o \ +./src/H264/h264_parser.o \ +./src/H264/h264_poc.o \ +./src/H264/ranges.o + +C_DEPS += \ +./src/H264/SPSParser.d + +CPP_DEPS += \ +./src/H264/H264Parser.d \ +./src/H264/h264_bit_reader.d \ +./src/H264/h264_parser.d \ +./src/H264/h264_poc.d \ +./src/H264/ranges.d + + +# Each subdirectory must supply rules for building sources it contributes +src/H264/%.o: ../src/H264/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + +src/H264/%.o: ../src/H264/%.c + @echo 'Building file: $<' + @echo 'Invoking: Cross GCC Compiler' + gcc -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Http/subdir.mk b/X64/src/Http/subdir.mk new file mode 100644 index 00000000..714ff38f --- /dev/null +++ b/X64/src/Http/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Http/HttpSession.cpp \ +../src/Http/strCoding.cpp + +OBJS += \ +./src/Http/HttpSession.o \ +./src/Http/strCoding.o + +CPP_DEPS += \ +./src/Http/HttpSession.d \ +./src/Http/strCoding.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Http/%.o: ../src/Http/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/MedaiFile/CRC/subdir.mk b/X64/src/MedaiFile/CRC/subdir.mk new file mode 100644 index 00000000..819027c5 --- /dev/null +++ b/X64/src/MedaiFile/CRC/subdir.mk @@ -0,0 +1,24 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/MedaiFile/CRC/crc32.cpp + +OBJS += \ +./src/MedaiFile/CRC/crc32.o + +CPP_DEPS += \ +./src/MedaiFile/CRC/crc32.d + + +# Each subdirectory must supply rules for building sources it contributes +src/MedaiFile/CRC/%.o: ../src/MedaiFile/CRC/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/MedaiFile/subdir.mk b/X64/src/MedaiFile/subdir.mk new file mode 100644 index 00000000..cfc89a80 --- /dev/null +++ b/X64/src/MedaiFile/subdir.mk @@ -0,0 +1,36 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/MedaiFile/HLSMaker.cpp \ +../src/MedaiFile/MediaReader.cpp \ +../src/MedaiFile/MediaRecorder.cpp \ +../src/MedaiFile/Mp4Maker.cpp \ +../src/MedaiFile/TSMaker.cpp + +OBJS += \ +./src/MedaiFile/HLSMaker.o \ +./src/MedaiFile/MediaReader.o \ +./src/MedaiFile/MediaRecorder.o \ +./src/MedaiFile/Mp4Maker.o \ +./src/MedaiFile/TSMaker.o + +CPP_DEPS += \ +./src/MedaiFile/HLSMaker.d \ +./src/MedaiFile/MediaReader.d \ +./src/MedaiFile/MediaRecorder.d \ +./src/MedaiFile/Mp4Maker.d \ +./src/MedaiFile/TSMaker.d + + +# Each subdirectory must supply rules for building sources it contributes +src/MedaiFile/%.o: ../src/MedaiFile/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Player/subdir.mk b/X64/src/Player/subdir.mk new file mode 100644 index 00000000..33f6abfb --- /dev/null +++ b/X64/src/Player/subdir.mk @@ -0,0 +1,30 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Player/MediaPlayer.cpp \ +../src/Player/Player.cpp \ +../src/Player/PlayerBase.cpp + +OBJS += \ +./src/Player/MediaPlayer.o \ +./src/Player/Player.o \ +./src/Player/PlayerBase.o + +CPP_DEPS += \ +./src/Player/MediaPlayer.d \ +./src/Player/Player.d \ +./src/Player/PlayerBase.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Player/%.o: ../src/Player/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/RTP/subdir.mk b/X64/src/RTP/subdir.mk new file mode 100644 index 00000000..862be208 --- /dev/null +++ b/X64/src/RTP/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/RTP/RtpMakerAAC.cpp \ +../src/RTP/RtpMakerH264.cpp + +OBJS += \ +./src/RTP/RtpMakerAAC.o \ +./src/RTP/RtpMakerH264.o + +CPP_DEPS += \ +./src/RTP/RtpMakerAAC.d \ +./src/RTP/RtpMakerH264.d + + +# Each subdirectory must supply rules for building sources it contributes +src/RTP/%.o: ../src/RTP/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Rtmp/subdir.mk b/X64/src/Rtmp/subdir.mk new file mode 100644 index 00000000..17608371 --- /dev/null +++ b/X64/src/Rtmp/subdir.mk @@ -0,0 +1,51 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Rtmp/RtmpMediaSource.cpp \ +../src/Rtmp/RtmpParser.cpp \ +../src/Rtmp/RtmpPlayer.cpp \ +../src/Rtmp/RtmpPlayerImp.cpp \ +../src/Rtmp/RtmpProtocol.cpp \ +../src/Rtmp/RtmpPusher.cpp \ +../src/Rtmp/RtmpSession.cpp \ +../src/Rtmp/RtmpToRtspMediaSource.cpp \ +../src/Rtmp/amf.cpp \ +../src/Rtmp/utils.cpp + +OBJS += \ +./src/Rtmp/RtmpMediaSource.o \ +./src/Rtmp/RtmpParser.o \ +./src/Rtmp/RtmpPlayer.o \ +./src/Rtmp/RtmpPlayerImp.o \ +./src/Rtmp/RtmpProtocol.o \ +./src/Rtmp/RtmpPusher.o \ +./src/Rtmp/RtmpSession.o \ +./src/Rtmp/RtmpToRtspMediaSource.o \ +./src/Rtmp/amf.o \ +./src/Rtmp/utils.o + +CPP_DEPS += \ +./src/Rtmp/RtmpMediaSource.d \ +./src/Rtmp/RtmpParser.d \ +./src/Rtmp/RtmpPlayer.d \ +./src/Rtmp/RtmpPlayerImp.d \ +./src/Rtmp/RtmpProtocol.d \ +./src/Rtmp/RtmpPusher.d \ +./src/Rtmp/RtmpSession.d \ +./src/Rtmp/RtmpToRtspMediaSource.d \ +./src/Rtmp/amf.d \ +./src/Rtmp/utils.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Rtmp/%.o: ../src/Rtmp/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Rtsp/subdir.mk b/X64/src/Rtsp/subdir.mk new file mode 100644 index 00000000..7081b51c --- /dev/null +++ b/X64/src/Rtsp/subdir.mk @@ -0,0 +1,48 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Rtsp/RtpBroadCaster.cpp \ +../src/Rtsp/RtpParser.cpp \ +../src/Rtsp/Rtsp.cpp \ +../src/Rtsp/RtspMediaSource.cpp \ +../src/Rtsp/RtspPlayer.cpp \ +../src/Rtsp/RtspPlayerImp.cpp \ +../src/Rtsp/RtspSession.cpp \ +../src/Rtsp/RtspToRtmpMediaSource.cpp \ +../src/Rtsp/UDPServer.cpp + +OBJS += \ +./src/Rtsp/RtpBroadCaster.o \ +./src/Rtsp/RtpParser.o \ +./src/Rtsp/Rtsp.o \ +./src/Rtsp/RtspMediaSource.o \ +./src/Rtsp/RtspPlayer.o \ +./src/Rtsp/RtspPlayerImp.o \ +./src/Rtsp/RtspSession.o \ +./src/Rtsp/RtspToRtmpMediaSource.o \ +./src/Rtsp/UDPServer.o + +CPP_DEPS += \ +./src/Rtsp/RtpBroadCaster.d \ +./src/Rtsp/RtpParser.d \ +./src/Rtsp/Rtsp.d \ +./src/Rtsp/RtspMediaSource.d \ +./src/Rtsp/RtspPlayer.d \ +./src/Rtsp/RtspPlayerImp.d \ +./src/Rtsp/RtspSession.d \ +./src/Rtsp/RtspToRtmpMediaSource.d \ +./src/Rtsp/UDPServer.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Rtsp/%.o: ../src/Rtsp/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/Shell/subdir.mk b/X64/src/Shell/subdir.mk new file mode 100644 index 00000000..928acb05 --- /dev/null +++ b/X64/src/Shell/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/Shell/CMD.cpp \ +../src/Shell/ShellSession.cpp + +OBJS += \ +./src/Shell/CMD.o \ +./src/Shell/ShellSession.o + +CPP_DEPS += \ +./src/Shell/CMD.d \ +./src/Shell/ShellSession.d + + +# Each subdirectory must supply rules for building sources it contributes +src/Shell/%.o: ../src/Shell/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/X64/src/subdir.mk b/X64/src/subdir.mk new file mode 100644 index 00000000..195a0b19 --- /dev/null +++ b/X64/src/subdir.mk @@ -0,0 +1,24 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/config.cpp + +OBJS += \ +./src/config.o + +CPP_DEPS += \ +./src/config.d + + +# Each subdirectory must supply rules for building sources it contributes +src/%.o: ../src/%.cpp + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -std=c++1y -DENABLE_FAAC -DENABLE_RTSP2RTMP -DENABLE_RTMP2RTSP -DENABLE_MEDIAFILE -DENABLE_X264 -I"/Users/xzl/git/ZLMediaKit/src" -I../../ZLToolKit/src -O3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/src/Codec/AACEncoder.cpp b/src/Codec/AACEncoder.cpp new file mode 100644 index 00000000..42d1dbfd --- /dev/null +++ b/src/Codec/AACEncoder.cpp @@ -0,0 +1,110 @@ +/* + * AACEncoder.cpp + * + * Created on: 2016年8月11日 + * Author: xzl + */ +#ifdef ENABLE_FAAC +#include "AACEncoder.h" +#include "Util/logger.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +using namespace ZL::Util; + +namespace ZL { +namespace Codec { + +AACEncoder::AACEncoder() { + +} + +AACEncoder::~AACEncoder() { + if (m_hEncoder != nullptr) { + faacEncClose(m_hEncoder); + m_hEncoder = nullptr; + } + if (m_pucAacBuf != nullptr) { + delete[] m_pucAacBuf; + m_pucAacBuf = nullptr; + } + if (m_pucPcmBuf != nullptr) { + delete[] m_pucPcmBuf; + m_pucPcmBuf = nullptr; + } +} + +bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) { + if (iSampleBit != 16) { + return false; + } + // (1) Open FAAC engine + m_hEncoder = faacEncOpen(iSampleRate, iChannels, &m_ulInputSamples, + &m_ulMaxOutputBytes); + if (m_hEncoder == NULL) { + return false; + } + m_pucAacBuf = new unsigned char[m_ulMaxOutputBytes]; + m_ulMaxInputBytes = m_ulInputSamples * iSampleBit / 8; + m_pucPcmBuf = new unsigned char[m_ulMaxInputBytes * 4]; + + // (2.1) Get current encoding configuration + faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_hEncoder); + if (pConfiguration == NULL) { + faacEncClose(m_hEncoder); + return false; + } + pConfiguration->aacObjectType =LOW; + pConfiguration->mpegVersion = 4; + pConfiguration->useTns = 1; + pConfiguration->shortctl = SHORTCTL_NORMAL; + pConfiguration->useLfe = 1; + pConfiguration->allowMidside = 1; + pConfiguration->bitRate = 0; + pConfiguration->bandWidth = 0; + pConfiguration->quantqual = 50; + pConfiguration->outputFormat = 1; + pConfiguration->inputFormat = FAAC_INPUT_16BIT; + + // (2.2) Set encoding configuration + if(!faacEncSetConfiguration(m_hEncoder, pConfiguration)){ + ErrorL << "faacEncSetConfiguration failed"; + faacEncClose(m_hEncoder); + return false; + } + return true; +} + +int AACEncoder::inputData(char *pcPcmBufr, int iLen, unsigned char **ppucOutBuffer) { + memcpy(m_pucPcmBuf + m_uiPcmLen, pcPcmBufr, iLen); + m_uiPcmLen += iLen; + if (m_uiPcmLen < m_ulMaxInputBytes) { + return 0; + } + + int nRet = faacEncEncode(m_hEncoder, (int32_t *) (m_pucPcmBuf), m_ulInputSamples, m_pucAacBuf, m_ulMaxOutputBytes); + m_uiPcmLen -= m_ulMaxInputBytes; + memmove(m_pucPcmBuf, m_pucPcmBuf + m_ulMaxInputBytes, m_uiPcmLen); + *ppucOutBuffer = m_pucAacBuf; + return nRet; +} + +} /* namespace Codec */ +} /* namespace ZL */ + +#endif //ENABLE_FAAC + + + + + + diff --git a/src/Codec/AACEncoder.h b/src/Codec/AACEncoder.h new file mode 100644 index 00000000..3facf8cb --- /dev/null +++ b/src/Codec/AACEncoder.h @@ -0,0 +1,38 @@ +/* + * AACEncoder.h + * + * Created on: 2016年8月11日 + * Author: xzl + */ + +#ifndef CODEC_AACENCODER_H_ +#define CODEC_AACENCODER_H_ + + +namespace ZL { +namespace Codec { + +class AACEncoder { +public: + AACEncoder(void); + virtual ~AACEncoder(void); + bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit); + int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer); + +private: + unsigned char *m_pucPcmBuf = nullptr; + unsigned int m_uiPcmLen = 0; + + unsigned char *m_pucAacBuf = nullptr; + void *m_hEncoder = nullptr; + + unsigned long m_ulInputSamples = 0; + unsigned long m_ulMaxInputBytes = 0; + unsigned long m_ulMaxOutputBytes = 0; + +}; + +} /* namespace Codec */ +} /* namespace ZL */ + +#endif /* CODEC_AACENCODER_H_ */ diff --git a/src/Codec/H264Encoder.cpp b/src/Codec/H264Encoder.cpp new file mode 100644 index 00000000..f4696a39 --- /dev/null +++ b/src/Codec/H264Encoder.cpp @@ -0,0 +1,349 @@ +/* + * H264Encoder.cpp + * + * Created on: 2016年8月11日 + * Author: xzl + */ +#ifdef ENABLE_X264 +#include "H264Encoder.h" + +#include "Util/TimeTicker.h" +using namespace ZL::Util; + +namespace ZL { +namespace Codec { + +H264Encoder::H264Encoder() { + +} + +H264Encoder::~H264Encoder() { + //* 清除图像区域 + if (m_pPicIn) { + delete m_pPicIn; + m_pPicIn = nullptr; + } + if (m_pPicOut) { + delete m_pPicOut; + m_pPicOut = nullptr; + } + + //* 关闭编码器句柄 + if (m_pX264Handle) { + x264_encoder_close(m_pX264Handle); + m_pX264Handle = nullptr; + } +} + + +/*typedef struct x264_param_t +{ + CPU 标志位 + unsigned int cpu; + int i_threads; 并行编码多帧 + int b_deterministic; 是否允许非确定性时线程优化 + int i_sync_lookahead; 线程超前缓冲 + + 视频属性 + int i_width; 宽度 + int i_height; 高度 + int i_csp; 编码比特流的CSP,仅支持i420,色彩空间设置 + int i_level_idc; level值的设置 + int i_frame_total; 编码帧的总数, 默认 0 +Vui参数集视频可用性信息视频标准化选项 + struct + { + they will be reduced to be 0 < x <= 65535 and prime + int i_sar_height; + int i_sar_width; 设置长宽比 + + int i_overscan; 0=undef, 1=no overscan, 2=overscan 过扫描线,默认"undef"(不设置),可选项:show(观看)/crop(去除) + + 见以下的值h264附件E + Int i_vidformat; 视频格式,默认"undef",component/pal/ntsc/secam/mac/undef + int b_fullrange; Specify full range samples setting,默认"off",可选项:off/on + int i_colorprim; 原始色度格式,默认"undef",可选项:undef/bt709/bt470m/bt470bg,smpte170m/smpte240m/film + int i_transfer; 转换方式,默认"undef",可选项:undef/bt709/bt470m/bt470bg/linear,log100/log316/smpte170m/smpte240m + int i_colmatrix; 色度矩阵设置,默认"undef",undef/bt709/fcc/bt470bg,smpte170m/smpte240m/GBR/YCgCo + int i_chroma_loc; both top & bottom色度样本指定,范围0~5,默认0 + } vui; + + int i_fps_num; + int i_fps_den; +这两个参数是由fps帧率确定的,赋值的过程见下: +{ float fps; +if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 ) + ; + else if( sscanf( value, "%f", &fps ) ) + { + p->i_fps_num = (int)(fps * 1000 + .5); + p->i_fps_den = 1000; + } + else + b_error = 1; + } +Value的值就是fps。 + + 流参数 + int i_frame_reference; 参考帧最大数目 + int i_keyint_max; 在此间隔设置IDR关键帧 + int i_keyint_min; 场景切换少于次值编码位I, 而不是 IDR. + int i_scenecut_threshold; 如何积极地插入额外的I帧 + int i_bframe; 两个相关图像间P帧的数目 + int i_bframe_adaptive; 自适应B帧判定 + int i_bframe_bias; 控制插入B帧判定,范围-100~+100,越高越容易插入B帧,默认0 + int b_bframe_pyramid; 允许部分B为参考帧 +去块滤波器需要的参数 + int b_deblocking_filter; + int i_deblocking_filter_alphac0; [-6, 6] -6 light filter, 6 strong + int i_deblocking_filter_beta; [-6, 6] idem + 熵编码 + int b_cabac; + int i_cabac_init_idc; + + int b_interlaced; 隔行扫描 + 量化 + int i_cqm_preset; 自定义量化矩阵(CQM),初始化量化模式为flat + char *psz_cqm_file; JM format读取JM格式的外部量化矩阵文件,自动忽略其他—cqm 选项 + uint8_t cqm_4iy[16]; used only if i_cqm_preset == X264_CQM_CUSTOM + uint8_t cqm_4ic[16]; + uint8_t cqm_4py[16]; + uint8_t cqm_4pc[16]; + uint8_t cqm_8iy[64]; + uint8_t cqm_8py[64]; + + 日志 + void (*pf_log)( void *, int i_level, const char *psz, va_list ); + void *p_log_private; + int i_log_level; + int b_visualize; + char *psz_dump_yuv; 重建帧的名字 + + 编码分析参数 + struct + { + unsigned int intra; 帧间分区 + unsigned int inter; 帧内分区 + + int b_transform_8x8; 帧间分区 + int b_weighted_bipred; 为b帧隐式加权 + int i_direct_mv_pred; 时间空间队运动预测 + int i_chroma_qp_offset; 色度量化步长偏移量 + + int i_me_method; 运动估计算法 (X264_ME_*) + int i_me_range; 整像素运动估计搜索范围 (from predicted mv) + int i_mv_range; 运动矢量最大长度(in pixels). -1 = auto, based on level + int i_mv_range_thread; 线程之间的最小空间. -1 = auto, based on number of threads. + int i_subpel_refine; 亚像素运动估计质量 + int b_chroma_me; 亚像素色度运动估计和P帧的模式选择 + int b_mixed_references; 允许每个宏块的分区在P帧有它自己的参考号 + int i_trellis; Trellis量化,对每个8x8的块寻找合适的量化值,需要CABAC,默认0 0:关闭1:只在最后编码时使用2:一直使用 + int b_fast_pskip; 快速P帧跳过检测 + int b_dct_decimate; 在P-frames转换参数域 + int i_noise_reduction; 自适应伪盲区 + float f_psy_rd; Psy RD strength + float f_psy_trellis; Psy trellis strength + int b_psy; Toggle all psy optimizations + + ,亮度量化中使用的无效区大小 + int i_luma_deadzone[2]; {帧间, 帧内} + + int b_psnr; 计算和打印PSNR信息 + int b_ssim; 计算和打印SSIM信息 + } analyse; + + 码率控制参数 + struct + { + int i_rc_method; X264_RC_* + + int i_qp_constant; 0-51 + int i_qp_min; 允许的最小量化值 + int i_qp_max; 允许的最大量化值 + int i_qp_step; 帧间最大量化步长 + + int i_bitrate; 设置平均码率 + float f_rf_constant; 1pass VBR, nominal QP + float f_rate_tolerance; + int i_vbv_max_bitrate; 平均码率模式下,最大瞬时码率,默认0(与-B设置相同) + int i_vbv_buffer_size; 码率控制缓冲区的大小,单位kbit,默认0 + float f_vbv_buffer_init; <=1: fraction of buffer_size. >1: kbit码率控制缓冲区数据保留的最大数据量与缓冲区大小之比,范围0~1.0,默认0.9 + float f_ip_factor; + float f_pb_factor; + + int i_aq_mode; psy adaptive QP. (X264_AQ_*) + float f_aq_strength; + int b_mb_tree; Macroblock-tree ratecontrol. + int i_lookahead; + + 2pass 多次压缩码率控制 + int b_stat_write; Enable stat writing in psz_stat_out + char *psz_stat_out; + int b_stat_read; Read stat from psz_stat_in and use it + char *psz_stat_in; + + 2pass params (same as ffmpeg ones) + float f_qcompress; 0.0 => cbr, 1.0 => constant qp + float f_qblur; 时间上模糊量化 + float f_complexity_blur; 时间上模糊复杂性 + x264_zone_t *zones; 码率控制覆盖 + int i_zones; number of zone_t's + char *psz_zones; 指定区的另一种方法 + } rc; + + Muxing parameters + int b_aud; 生成访问单元分隔符 + int b_repeat_headers; 在每个关键帧前放置SPS/PPS + int i_sps_id; SPS 和 PPS id 号 + + 切片(像条)参数 + int i_slice_max_size; 每片字节的最大数,包括预计的NAL开销. + int i_slice_max_mbs; 每片宏块的最大数,重写 i_slice_count + int i_slice_count; 每帧的像条数目: 设置矩形像条. + + Optional callback for freeing this x264_param_t when it is done being used. + * Only used when the x264_param_t sits in memory for an indefinite period of time, + * i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones. + * Not used when x264_encoder_reconfig is called directly. + void (*param_free)( void* ); +} x264_param_t;*/ + +bool H264Encoder::init(int iWidth, int iHeight, int iFps) { + if (m_pX264Handle) { + return true; + } + x264_param_t X264Param, *pX264Param = &X264Param; + //* 配置参数 + //* 使用默认参数 + x264_param_default_preset(pX264Param, "ultrafast", "zerolatency"); + + //* cpuFlags + pX264Param->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //* 取空缓冲区继续使用不死锁的保证. + //* video Properties + pX264Param->i_width = iWidth; //* 宽度. + pX264Param->i_height = iHeight; //* 高度 + pX264Param->i_frame_total = 0; //* 编码总帧数.不知道用0. + pX264Param->i_keyint_max = iFps * 3; //ffmpeg:gop_size 关键帧最大间隔 + pX264Param->i_keyint_min = iFps * 1; //ffmpeg:keyint_min 关键帧最小间隔 + //* Rate control Parameters + pX264Param->rc.i_bitrate = 5000; //* 码率(比特率,单位Kbps) + pX264Param->rc.i_qp_step = 1; //最大的在帧与帧之间进行切变的量化因子的变化量。ffmpeg:max_qdiff + pX264Param->rc.i_qp_min = 10; //ffmpeg:qmin;最小的量化因子。取值范围1-51。建议在10-30之间。 + pX264Param->rc.i_qp_max = 41; //ffmpeg:qmax;最大的量化因子。取值范围1-51。建议在10-30之间。 + pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定 + pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径 + pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。 + //该值不影响解码的速度,但是越大解码 + //所需的内存越大。这个值在一般情况下 + //越大效果越好,但是超过6以后效果就 + //不明显了。 + + pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis + //pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式 + pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur + + //* bitstream parameters + /*open-GOP + 码流里面包含B帧的时候才会出现open-GOP。 + 一个GOP里面的某一帧在解码时要依赖于前一个GOP的某些帧, + 这个GOP就称为open-GOP。 + 有些解码器不能完全支持open-GOP码流, + 例如蓝光解码器,因此在x264里面open-GOP是默认关闭的。 + 对于解码端,接收到的码流如果如下:I0 B0 B1 P0 B2 B3...这就是一个open-GOP码流(I帧后面紧跟B帧)。 + 因此B0 B1的解码需要用到I0前面一个GOP的数据,B0 B1的dts是小于I0的。 + 如果码流如下: I0 P0 B0 B1 P1 B2 B3...这就是一个close-GOP码流, + I0后面所有帧的解码不依赖于I0前面的帧,I0后面所有帧的dts都比I0的大。 + 如果码流是IDR0 B0 B1 P0 B2 B3...那个这个GOP是close-GOP,B0,B1虽然dst比IDR0小, + 但编解码端都刷新了参考缓冲,B0,B1参考不到前向GOP帧。 + 对于编码端,如果编码帧类型决定如下: ...P0 B1 B2 P3 B4 B5 I6这就会输出open-Gop码流 (P0 P3 B1 B2 I6 B4 B5...), + B4 B5的解码依赖P3。 + 如果编码帧类型决定如下...P0 B1 B2 P3 B4 P5 I6这样就不会输出open-GOP码流(P0 P3 B1 B2 P5 B4 I6...)。 + 两者区别在于I6前面的第5帧是设置为B帧还是P帧, + 如果一个GOP的最后一帧(上例中是第5帧)设置为B帧, + 这个码流就是open-GOP,设置为P帧就是close-GOP。 + 由于B帧压缩性能好于P帧,因此open-GOP在编码性能上稍微优于close-GOP, + 但为了兼容性和少一些麻烦,还是把opne-GOP关闭的好。*/ + pX264Param->b_open_gop = 0; + pX264Param->i_bframe = 0; //最大B帧数. + pX264Param->i_bframe_pyramid = 0; + pX264Param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; + //* Log + pX264Param->i_log_level = X264_LOG_ERROR; + + //* muxing parameters + pX264Param->i_fps_den = 1; //* 帧率分母 + pX264Param->i_fps_num = iFps; //* 帧率分子 + pX264Param->i_timebase_den = pX264Param->i_fps_num; + pX264Param->i_timebase_num = pX264Param->i_fps_den; + + pX264Param->analyse.i_subpel_refine = 1; //这个参数控制在运动估算过程中质量和速度的权衡。Subq=5可以压缩>10%于subq=1。1-7 + pX264Param->analyse.b_fast_pskip = 1; //在P帧内执行早期快速跳跃探测。这个经常在没有任何损失的前提下提高了速度。 + + pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度 + pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧,0 否 1,放 + + //* 设置Profile.使用baseline + x264_param_apply_profile(pX264Param, "high"); + + //* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264 + //* 的参数.通过x264_encoder_reconfig更新X264的参数 + m_pX264Handle = x264_encoder_open(pX264Param); + if (!m_pX264Handle) { + return false; + } + m_pPicIn = new x264_picture_t; + m_pPicOut = new x264_picture_t; + x264_picture_init(m_pPicIn); + x264_picture_init(m_pPicOut); + m_pPicIn->img.i_csp = X264_CSP_I420; + m_pPicIn->img.i_plane = 3; + return true; +} + +int H264Encoder::inputData(char* apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame** ppFrame) { + //TimeTicker1(5); + m_pPicIn->img.i_stride[0] = aiYuvLen[0]; + m_pPicIn->img.i_stride[1] = aiYuvLen[1]; + m_pPicIn->img.i_stride[2] = aiYuvLen[2]; + m_pPicIn->img.plane[0] = (uint8_t *) apcYuv[0]; + m_pPicIn->img.plane[1] = (uint8_t *) apcYuv[1]; + m_pPicIn->img.plane[2] = (uint8_t *) apcYuv[2]; + m_pPicIn->i_pts = i64Pts; + int iNal; + x264_nal_t* pNals; + + int iResult = x264_encoder_encode(m_pX264Handle, &pNals, &iNal, m_pPicIn, + m_pPicOut); + if (iResult <= 0) { + return 0; + } + for (int i = 0; i < iNal; i++) { + x264_nal_t pNal = pNals[i]; + m_aFrames[i].iType = pNal.i_type; + m_aFrames[i].iLength = pNal.i_payload; + m_aFrames[i].pucData = pNal.p_payload; + } + *ppFrame = m_aFrames; + return iNal; +} + +} /* namespace Codec */ +} /* namespace ZL */ + +#endif //ENABLE_X264 + + + + + + + + + + + + + + + + diff --git a/src/Codec/H264Encoder.h b/src/Codec/H264Encoder.h new file mode 100644 index 00000000..5d5ff879 --- /dev/null +++ b/src/Codec/H264Encoder.h @@ -0,0 +1,48 @@ +/* + * H264Encoder.h + * + * Created on: 2016年8月11日 + * Author: xzl + */ + +#ifndef CODEC_H264ENCODER_H_ +#define CODEC_H264ENCODER_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +#include + +#ifdef __cplusplus +} + +#endif //__cplusplus + +namespace ZL { +namespace Codec { + +class H264Encoder { +public: + typedef struct { + int iType; + int iLength; + uint8_t *pucData; + } H264Frame; + + H264Encoder(void); + virtual ~H264Encoder(void); + bool init(int iWidth, int iHeight, int iFps); + int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame); +private: + x264_t* m_pX264Handle = nullptr; + x264_picture_t* m_pPicIn = nullptr; + x264_picture_t* m_pPicOut = nullptr; + H264Frame m_aFrames[10]; +}; + +} /* namespace Codec */ +} /* namespace ZL */ + +#endif /* CODEC_H264ENCODER_H_ */ diff --git a/src/Device/Device.cpp b/src/Device/Device.cpp new file mode 100644 index 00000000..0fa4dd77 --- /dev/null +++ b/src/Device/Device.cpp @@ -0,0 +1,256 @@ +/* + * Device.cpp + * + * Created on: 2016年8月10日 + * Author: xzl + */ + +#include "Device.h" +#include "Util/logger.h" +#include +#include "Util/util.h" +#include +#include "base64.h" + +#include "Util/TimeTicker.h" +using namespace ZL::Util; + +namespace ZL { +namespace DEV { + + +///////////////////////////////////////////////////////////////////////////////// +#ifdef ENABLE_RTSP2RTMP +DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) : + m_mediaSrc(new RtspToRtmpMediaSource(strApp,strId , bLiveStream)) { +#else +DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) : + m_mediaSrc(new RtspToRtmpMediaSource(strApp,strId )) { +#endif //ENABLE_RTSP2RTMP + m_strSDP = "v=0\r\n"; + m_strSDP += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n"; + m_strSDP += "s=RTSP Session, streamed by the ZL\r\n"; + m_strSDP += "i=ZL Live Stream\r\n"; + m_strSDP += "c=IN IP4 0.0.0.0\r\n"; + m_strSDP += "t=0 0\r\n"; + //直播,时间长度永远 + if(fDuration <= 0 || bLiveStream){ + m_strSDP += "a=range:npt=0-\r\n"; + }else{ + m_strSDP += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl; + } + m_strSDP += "a=control:*\r\n"; +} +DevChannel::~DevChannel() { +} + +void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) { + //TimeTicker1(50); +#ifdef ENABLE_X264 + if (!m_pH264Enc) { + m_pH264Enc.reset(new H264Encoder()); + if (!m_pH264Enc->init(m_video->iWidth, m_video->iHeight, m_video->iFrameRate)) { + m_pH264Enc.reset(); + WarnL << "H264Encoder init failed!"; + } + } + if (m_pH264Enc) { + H264Encoder::H264Frame *pOut; + int iFrames = m_pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut); + for (int i = 0; i < iFrames; i++) { + inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp); + } + } +#else + ErrorL << "libx264 was not enabled!"; +#endif //ENABLE_X264 +} + +void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) { +#ifdef ENABLE_FAAC + if (!m_pAacEnc) { + m_pAacEnc.reset(new AACEncoder()); + if (!m_pAacEnc->init(m_audio->iSampleRate, m_audio->iChannel, m_audio->iSampleBit)) { + m_pAacEnc.reset(); + WarnL << "AACEncoder init failed!"; + } + } + if (m_pAacEnc) { + unsigned char *pucOut; + int iRet = m_pAacEnc->inputData(pcData, iDataLen, &pucOut); + if (iRet > 0) { + inputAAC((char *) pucOut, iRet, uiStamp); + } + } +#else + ErrorL << "libfaac was not enabled!"; +#endif //ENABLE_FAAC +} + +void DevChannel::inputH264(char* pcData, int iDataLen, uint32_t uiStamp) { + if (!m_pRtpMaker_h264) { + uint32_t ui32Ssrc; + memcpy(&ui32Ssrc, makeRandStr(4, false).data(), 4); + auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) { + m_mediaSrc->onGetRTP(pkt,bKeyPos); + }; + static uint32_t videoMtu = mINI::Instance()[Config::Rtp::kVideoMtuSize].as(); + m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu)); + } + if (!m_bSdp_gotH264 && m_video) { + makeSDP_264((unsigned char*) pcData, iDataLen); + } + int iOffset = 4; + if (memcmp("\x00\x00\x01", pcData, 3) == 0) { + iOffset = 3; + } + m_pRtpMaker_h264->makeRtp(pcData + iOffset, iDataLen - iOffset, uiStamp); +} + +void DevChannel::inputAAC(char* pcData, int iDataLen, uint32_t uiStamp) { + if (!m_pRtpMaker_aac) { + uint32_t ssrc; + memcpy(&ssrc, makeRandStr(8, false).data() + 4, 4); + auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) { + m_mediaSrc->onGetRTP(pkt,keyPos); + }; + static uint32_t audioMtu = mINI::Instance()[Config::Rtp::kAudioMtuSize].as(); + m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,m_audio->iSampleRate)); + } + if (!m_bSdp_gotAAC && m_audio) { + makeSDP_AAC((unsigned char*) pcData, iDataLen); + } + m_pRtpMaker_aac->makeRtp(pcData + 7, iDataLen - 7, uiStamp); + +} + +inline void DevChannel::makeSDP_264(unsigned char *pcData, int iDataLen) { + int offset = 4; + if (memcmp("\x00\x00\x01", pcData, 3) == 0) { + offset = 3; + } + switch (pcData[offset] & 0x1F) { + case 7:/*SPS frame*/ + { + if (m_uiSPSLen != 0) { + break; + } + memcpy(m_aucSPS, pcData + offset, iDataLen - offset); + m_uiSPSLen = iDataLen - offset; + } + break; + case 8:/*PPS frame*/ + { + if (m_uiPPSLen != 0) { + break; + } + memcpy(m_aucPPS, pcData + offset, iDataLen - offset); + m_uiPPSLen = iDataLen - offset; + } + break; + default: + break; + } + if (!m_uiSPSLen || !m_uiPPSLen) { + return; + } + + char acTmp[256]; + int profile_level_id = 0; + if (m_uiSPSLen >= 4) { // sanity check + profile_level_id = (m_aucSPS[1] << 16) | (m_aucSPS[2] << 8) | m_aucSPS[3]; // profile_idc|constraint_setN_flag|level_idc + } + + //视频通道 + m_strSDP += StrPrinter << "m=video 0 RTP/AVP " + << m_pRtpMaker_h264->getPlayloadType() << "\r\n" << endl; + m_strSDP += "b=AS:5100\r\n"; + m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType() + << " H264/" << m_pRtpMaker_h264->getSampleRate() << "\r\n" << endl; + m_strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_h264->getPlayloadType() + << " packetization-mode=1;profile-level-id=" << endl; + + memset(acTmp, 0, sizeof(acTmp)); + sprintf(acTmp, "%06X", profile_level_id); + m_strSDP += acTmp; + m_strSDP += ";sprop-parameter-sets="; + memset(acTmp, 0, sizeof(acTmp)); + av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucSPS, m_uiSPSLen); + //WarnL<<"SPS base64:"<iFrameRate > 0 && m_video->iHeight > 0 && m_video->iWidth > 0) { + m_strSDP += "a=framerate:"; + m_strSDP += StrPrinter << m_video->iFrameRate << endl; + m_strSDP += StrPrinter << "\r\na=framesize:" + << m_pRtpMaker_h264->getPlayloadType() << " " << endl; + m_strSDP += StrPrinter << m_video->iWidth << endl; + m_strSDP += "-"; + m_strSDP += StrPrinter << m_video->iHeight << endl; + m_strSDP += "\r\n"; + } + m_strSDP += StrPrinter << "a=control:trackID=" + << m_pRtpMaker_h264->getInterleaved() / 2 << "\r\n" << endl; + m_bSdp_gotH264 = true; + if (m_audio) { + if (m_bSdp_gotAAC) { + makeSDP(m_strSDP); + } + } else { + makeSDP(m_strSDP); + } +} + +inline void DevChannel::makeSDP_AAC(unsigned char *fixedHeader, int dataLen) { + auto audioSpecificConfig = makeAdtsConfig(fixedHeader); + if (audioSpecificConfig.size() != 2) { + return; + } + + char fConfigStr[5] = { 0 }; + sprintf(fConfigStr, "%02X%02x", (uint8_t)audioSpecificConfig[0],(uint8_t)audioSpecificConfig[1]); + + m_strSDP += StrPrinter << "m=audio 0 RTP/AVP " + << m_pRtpMaker_aac->getPlayloadType() << "\r\n" << endl; + m_strSDP += "b=AS:96\r\n"; + m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType() + << " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n" + << endl; + m_strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_aac->getPlayloadType() + << " streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=" + << endl; + m_strSDP += fConfigStr; + m_strSDP += "\r\n"; + m_strSDP += StrPrinter << "a=control:trackID=" + << m_pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl; + + m_bSdp_gotAAC = true; + if (m_video) { + if (m_bSdp_gotH264) { + makeSDP(m_strSDP); + } + } else { + makeSDP(m_strSDP); + } +} + +void DevChannel::makeSDP(const string& strSdp) { + m_mediaSrc->onGetSDP(strSdp); + m_mediaSrc->regist(); +} + +void DevChannel::initVideo(const VideoInfo& info) { + m_video.reset(new VideoInfo(info)); +} + +void DevChannel::initAudio(const AudioInfo& info) { + m_audio.reset(new AudioInfo(info)); +} +} /* namespace DEV */ +} /* namespace ZL */ + diff --git a/src/Device/Device.h b/src/Device/Device.h new file mode 100644 index 00000000..172bf3ee --- /dev/null +++ b/src/Device/Device.h @@ -0,0 +1,108 @@ +/* + * Device.h + * + * Created on: 2016年8月10日 + * Author: xzl + */ + +#ifndef DEVICE_DEVICE_H_ +#define DEVICE_DEVICE_H_ +#include +#include +#include +#include +#include "Util/util.h" +#include "RTP/RtpMakerAAC.h" +#include "RTP/RtpMakerH264.h" +#include "Rtsp/RtspToRtmpMediaSource.h" +using namespace std; +using namespace ZL::Rtsp; +using namespace ZL::Util; + +#ifdef ENABLE_FAAC +#include "Codec/AACEncoder.h" +using namespace ZL::Codec; +#endif //ENABLE_FAAC + +#ifdef ENABLE_X264 +#include "Codec/H264Encoder.h" +using namespace ZL::Codec; +#endif //ENABLE_X264 + +using namespace ZL::Rtsp; +namespace ZL { +namespace DEV { + +class VideoInfo { +public: + int iWidth; + int iHeight; + float iFrameRate; +}; +class AudioInfo { +public: + int iChannel; + int iSampleBit; + int iSampleRate; +}; + + +class DevChannel { +public: + typedef std::shared_ptr Ptr; + DevChannel(const char *strApp, const char *strId,float fDuration = 0,bool bLiveStream = true); + virtual ~DevChannel(); + + void initVideo(const VideoInfo &info); + void initAudio(const AudioInfo &info); + + void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp); + void inputPCM(char *pcData, int iDataLen, uint32_t uiStamp); + + void inputH264(char *pcData, int iDataLen, uint32_t uiStamp); + void inputAAC(char *pcData, int iDataLen, uint32_t uiStamp); +#ifdef ENABLE_RTSP2RTMP + int readerCount() { + return m_mediaSrc ? m_mediaSrc->readerCount() : 0; + } + void updateTimeStamp(uint32_t uiStamp){ + m_mediaSrc->updateTimeStamp(uiStamp); + } +#endif //ENABLE_RTSP2RTMP + void setOnSeek(const function &onSeek){ + m_mediaSrc->setOnSeek(onSeek); + } + void setOnStamp(const function &cb) { + m_mediaSrc->setOnStamp(cb); + } +private: + inline void makeSDP_264(unsigned char *pucData, int iDataLen); + inline void makeSDP_AAC(unsigned char *pucData, int iDataLen); + inline void makeSDP(const string& strSdp); +#ifdef ENABLE_X264 + std::shared_ptr m_pH264Enc; +#endif //ENABLE_X264 + +#ifdef ENABLE_FAAC + std::shared_ptr m_pAacEnc; +#endif //ENABLE_FAAC + RtpMaker_AAC::Ptr m_pRtpMaker_aac; + RtpMaker_H264::Ptr m_pRtpMaker_h264; + RtspToRtmpMediaSource::Ptr m_mediaSrc; + string m_strSDP; + bool m_bSdp_gotH264 = false; + bool m_bSdp_gotAAC = false; + + unsigned char m_aucSPS[256]; + unsigned int m_uiSPSLen = 0; + unsigned char m_aucPPS[256]; + unsigned int m_uiPPSLen = 0; + std::shared_ptr m_video; + std::shared_ptr m_audio; +}; + + +} /* namespace DEV */ +} /* namespace ZL */ + +#endif /* DEVICE_DEVICE_H_ */ diff --git a/src/Device/PlayerProxy.cpp b/src/Device/PlayerProxy.cpp new file mode 100644 index 00000000..f306de0d --- /dev/null +++ b/src/Device/PlayerProxy.cpp @@ -0,0 +1,153 @@ +/* + * PlyerProxy.cpp + * + * Created on: 2016年12月6日 + * Author: xzl + */ + +#include "PlayerProxy.h" +#include "Thread/AsyncTaskThread.h" +#include "Util/MD5.h" +#include "Util/logger.h" +#include "config.h" +#include "Util/mini.hpp" + +using namespace ZL::Util; +using namespace ZL::Thread; + +namespace ZL { +namespace DEV { + +PlayerProxy::PlayerProxy(const char *strApp,const char *strSrc){ + m_strApp = strApp; + m_strSrc = strSrc; +} + +void PlayerProxy::play(const char* strUrl, const char *strUser, + const char *strPwd, PlayerBase::eRtpType eType, uint32_t iSecond) { + m_aliveSecond = iSecond; + string strUrlTmp(strUrl); + string strUserTmp(strUser); + string strPwdTmp(strPwd); + + m_pPlayer.reset(new MediaPlayer()); + m_pPlayer->play(strUrl, strUser, strPwd, eType); + weak_ptr weakSelf = shared_from_this(); + m_pPlayer->setOnVideoCB( [weakSelf,strUrlTmp](const H264Frame &data ) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + if(strongSelf->m_pChn){ + strongSelf->m_pChn->inputH264((char *)data.data.data(), data.data.size(), data.timeStamp); + }else{ + strongSelf->initMedia(); + } + strongSelf->checkExpired(); + }); + m_pPlayer->setOnAudioCB( [weakSelf,strUrlTmp](const AdtsFrame &data ) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + if(strongSelf->m_pChn){ + strongSelf->m_pChn->inputAAC((char *)data.data, data.aac_frame_length, data.timeStamp); + }else{ + strongSelf->initMedia(); + } + strongSelf->checkExpired(); + }); + + std::shared_ptr piFailedCnt(new uint64_t(0)); //连续播放失败次数 + m_pPlayer->setOnPlayResult([weakSelf,strUrlTmp,strUserTmp,strPwdTmp,eType,piFailedCnt](const SockException &err) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + static uint64_t replayCnt = mINI::Instance()[Config::Proxy::kReplayCount].as(); + if(!err) { + // 播放成功 + *piFailedCnt = 0;//连续播放失败次数清0 + }else if(*piFailedCnt < replayCnt) { + // 播放失败,延时重试播放 + strongSelf->rePlay(strUrlTmp, strUserTmp, strPwdTmp, eType,(*piFailedCnt)++); + }else{ + strongSelf->expired(); + } + }); + weak_ptr weakPtr= m_pPlayer; + m_pPlayer->setOnShutdown([weakSelf,weakPtr,strUrlTmp,strUserTmp,strPwdTmp,eType,piFailedCnt](const SockException &err) { + auto strongSelf = weakSelf.lock(); + if(!strongSelf) { + return; + } + if(strongSelf->m_pChn) { + strongSelf->m_pChn.reset(); + } + //播放异常中断,延时重试播放 + static uint64_t replayCnt = mINI::Instance()[Config::Proxy::kReplayCount].as(); + if(*piFailedCnt < replayCnt) { + strongSelf->rePlay(strUrlTmp, strUserTmp, strPwdTmp, eType,(*piFailedCnt)++); + }else{ + strongSelf->expired(); + } + }); +} + +PlayerProxy::~PlayerProxy() { + auto iTaskId = reinterpret_cast(this); + AsyncTaskThread::Instance().CancelTask(iTaskId); +} +void PlayerProxy::rePlay(const string &strUrl, const string &strUser, const string &strPwd, PlayerBase::eRtpType eType, uint64_t iFailedCnt){ + checkExpired(); + auto iTaskId = reinterpret_cast(this); + auto iDelay = MAX((uint64_t)2 * 1000, MIN(iFailedCnt * 3000,(uint64_t)60*1000)); + weak_ptr weakPtr = m_pPlayer; + AsyncTaskThread::Instance().CancelTask(iTaskId); + AsyncTaskThread::Instance().DoTaskDelay(iTaskId, iDelay, [weakPtr,strUrl,strUser,strPwd,eType,iFailedCnt]() { + //播放失败次数越多,则延时越长 + auto strongPlayer = weakPtr.lock(); + if(!strongPlayer) { + return false; + } + WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl; + strongPlayer->play(strUrl.data(), strUser.data(), strPwd.data(), eType); + return false; + }); +} +void PlayerProxy::initMedia() { + if (!m_pPlayer->isInited()) { + return; + } + m_pChn.reset(new DevChannel(m_strApp.data(),m_strSrc.data(),m_pPlayer->getDuration())); + if (m_pPlayer->containVideo()) { + VideoInfo info; + info.iFrameRate = m_pPlayer->getVideoFps(); + info.iWidth = m_pPlayer->getVideoWidth(); + info.iHeight = m_pPlayer->getVideoHeight(); + m_pChn->initVideo(info); + } + if (m_pPlayer->containAudio()) { + AudioInfo info; + info.iSampleRate = m_pPlayer->getAudioSampleRate(); + info.iChannel = m_pPlayer->getAudioChannel(); + info.iSampleBit = m_pPlayer->getAudioSampleBit(); + m_pChn->initAudio(info); + } +} + +void PlayerProxy::checkExpired() { + if(m_aliveSecond && m_aliveTicker.elapsedTime() > m_aliveSecond * 1000){ + //到期 + expired(); + } +} + +void PlayerProxy::expired() { + if(onExpired){ + onExpired(); + } +} + +} /* namespace Player */ +} /* namespace ZL */ diff --git a/src/Device/PlayerProxy.h b/src/Device/PlayerProxy.h new file mode 100644 index 00000000..967fa35a --- /dev/null +++ b/src/Device/PlayerProxy.h @@ -0,0 +1,48 @@ +/* + * PlyerProxy.h + * + * Created on: 2016年12月6日 + * Author: xzl + */ + +#ifndef SRC_DEVICE_PLAYERPROXY_H_ +#define SRC_DEVICE_PLAYERPROXY_H_ + +#include "Device.h" +#include +#include "Player/MediaPlayer.h" +#include "Util/TimeTicker.h" + +using namespace std; +using namespace ZL::Player; + +namespace ZL { +namespace DEV { + +class PlayerProxy : public std::enable_shared_from_this{ +public: + typedef std::shared_ptr Ptr; + PlayerProxy(const char *strApp, const char *strSrc); + void play(const char* strUrl, const char *strUser = "", const char *strPwd = "",PlayerBase::eRtpType eType = PlayerBase::RTP_TCP,uint32_t iSecond = 0); + virtual ~PlayerProxy(); + void setOnExpired(const function &cb){ + onExpired = cb; + } +private : + MediaPlayer::Ptr m_pPlayer; + DevChannel::Ptr m_pChn; + Ticker m_aliveTicker; + uint32_t m_aliveSecond = 0; + function onExpired; + string m_strApp; + string m_strSrc; + void initMedia(); + void rePlay(const string &strUrl, const string &strUser, const string &strPwd, PlayerBase::eRtpType eType,uint64_t iFailedCnt); + void checkExpired(); + void expired(); +}; + +} /* namespace Player */ +} /* namespace ZL */ + +#endif /* SRC_DEVICE_PLAYERPROXY_H_ */ diff --git a/src/Device/base64.cpp b/src/Device/base64.cpp new file mode 100644 index 00000000..f649bfde --- /dev/null +++ b/src/Device/base64.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief Base64 encode/decode + * @author Ryan Martell (with lots of Michael) + */ + +//#include "common.h" +#include "stdio.h" +#include "base64.h" + +#include +/* ---------------- private code */ +static const uint8_t map2[] = +{ + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 +}; + +int av_base64_decode(uint8_t *out, const char *in, int out_size) +{ + int i, v; + uint8_t *dst = out; + + v = 0; + for (i = 0; in[i] && in[i] != '='; i++) { + unsigned int index= in[i]-43; + if (index>=FF_ARRAY_ELEMS(map2) || map2[index] == 0xff) + return -1; + v = (v << 6) + map2[index]; + if (i & 3) { + if (dst - out < out_size) { + *dst++ = v >> (6 - 2 * (i & 3)); + } + } + } + + return dst - out; +} + +/***************************************************************************** +* b64_encode: Stolen from VLC's http.c. +* Simplified by Michael. +* Fixed edge cases and made it work from data (vs. strings) by Ryan. +*****************************************************************************/ + +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *ret, *dst; + unsigned i_bits = 0; + int i_shift = 0; + int bytes_remaining = in_size; + + if (in_size >= UINT_MAX / 4 || out_size < AV_BASE64_SIZE(in_size)) + { + return NULL; + } + ret = dst = out; + while (bytes_remaining) { + i_bits = (i_bits << 8) + *in++; + bytes_remaining--; + i_shift += 8; + + do { + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; + i_shift -= 6; + } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0)); + } + while ((dst - ret) & 3) + *dst++ = '='; + *dst = '\0'; + + return ret; +} + +#ifdef TEST + +#undef printf + +#define MAX_DATA_SIZE 1024 +#define MAX_ENCODED_SIZE 2048 + +static int test_encode_decode(const uint8_t *data, unsigned int data_size, + const char *encoded_ref) +{ + char encoded[MAX_ENCODED_SIZE]; + uint8_t data2[MAX_DATA_SIZE]; + int data2_size, max_data2_size = MAX_DATA_SIZE; + + if (!av_base64_encode(encoded, MAX_ENCODED_SIZE, data, data_size)) { + printf("Failed: cannot encode the input data\n"); + return 1; + } + if (encoded_ref && strcmp(encoded, encoded_ref)) { + printf("Failed: encoded string differs from reference\n" + "Encoded:\n%s\nReference:\n%s\n", encoded, encoded_ref); + return 1; + } + + if ((data2_size = av_base64_decode(data2, encoded, max_data2_size)) < 0) { + printf("Failed: cannot decode the encoded string\n" + "Encoded:\n%s\n", encoded); + return 1; + } + if (memcmp(data2, data, data_size)) { + printf("Failed: encoded/decoded data differs from original data\n"); + return 1; + } + + printf("Passed!\n"); + return 0; +} + +int main(void) +{ + int i, error_count = 0; + struct test { + const uint8_t *data; + const char *encoded_ref; + } tests[] = { + { "", ""}, + { "1", "MQ=="}, + { "22", "MjI="}, + { "333", "MzMz"}, + { "4444", "NDQ0NA=="}, + { "55555", "NTU1NTU="}, + { "666666", "NjY2NjY2"}, + { "abc:def", "YWJjOmRlZg=="}, + }; + + printf("Encoding/decoding tests\n"); + for (i = 0; i < FF_ARRAY_ELEMS(tests); i++) + error_count += test_encode_decode(tests[i].data, strlen(tests[i].data), tests[i].encoded_ref); + + return error_count; +} + +#endif diff --git a/src/Device/base64.h b/src/Device/base64.h new file mode 100644 index 00000000..6da4f28f --- /dev/null +++ b/src/Device/base64.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#ifndef AVUTIL_BASE64_H +#define AVUTIL_BASE64_H + +#include + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the output buffer, must be at + * least AV_BASE64_SIZE(in_size) + * @param in_size size in bytes of the 'in' buffer + * @return 'out' or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + +#endif /* AVUTIL_BASE64_H */ diff --git a/src/H264/H264Parser.cpp b/src/H264/H264Parser.cpp new file mode 100644 index 00000000..d1b44dc5 --- /dev/null +++ b/src/H264/H264Parser.cpp @@ -0,0 +1,100 @@ +// +// H264Parser.cpp +// MediaPlayer +// +// Created by xzl on 2017/1/16. +// Copyright © 2017年 jizan. All rights reserved. +// + +#include "H264Parser.h" +#include "Util/logger.h" +using namespace ZL::Util; + +H264Parser::H264Parser(){ + +} +H264Parser::~H264Parser(){ + +} +void H264Parser::inputH264(const string &h264,uint32_t dts){ + + m_parser.SetStream((const uint8_t *)h264.data(), h264.size()); + while (true) { + if(media::H264Parser::kOk != m_parser.AdvanceToNextNALU(&m_nalu)){ + break; + } + + switch (m_nalu.nal_unit_type) { + case media::H264NALU::kNonIDRSlice: + case media::H264NALU::kIDRSlice:{ + if(media::H264Parser::kOk == m_parser.ParseSliceHeader(m_nalu, &m_shdr)){ + const media::H264SPS *pPps = m_parser.GetSPS(m_shdr.pic_parameter_set_id); + if (pPps) { + m_poc.ComputePicOrderCnt(pPps, m_shdr, &m_iNowPOC); + computePts(dts); + } + } + } + break; + case media::H264NALU::kSPS:{ + int sps_id; + m_parser.ParseSPS(&sps_id); + } + break; + case media::H264NALU::kPPS:{ + int pps_id; + m_parser.ParsePPS(&pps_id); + } + break; + default: + break; + } + } +} + +void H264Parser::computePts(uint32_t iNowDTS) { + auto iPOCInc = m_iNowPOC - m_iLastPOC; + if (m_shdr.slice_type % 5 == 1) { + //这是B帧 + m_iNowPTS = m_iLastPTS + m_iMsPerPOC * (iPOCInc); + } else { + //这是I帧或者P帧 + m_iNowPTS = iNowDTS; + //计算每一POC的时间 + if(iPOCInc == 0){ + WarnL << "iPOCInc = 0," << m_iNowPOC << " " << m_iLastPOC; + }else{ + m_iMsPerPOC = (m_iNowPTS - m_iLastPTS) / iPOCInc; + } + m_iLastPTS = m_iNowPTS; + m_iLastPOC = m_iNowPOC; + } + + +// DebugL << m_shdr.slice_type +// <<"\r\nNOW:" +// << m_iNowPOC << " " +// << m_iNowPTS << " " +// << iNowDTS << " " +// << "\r\nLST:" +// << m_iLastPOC << " " +// << m_iLastPTS << " " +// << m_iMsPerPOC << endl; + +} + + + + + + + + + + + + + + + + diff --git a/src/H264/H264Parser.h b/src/H264/H264Parser.h new file mode 100644 index 00000000..662ce33b --- /dev/null +++ b/src/H264/H264Parser.h @@ -0,0 +1,56 @@ +// +// H264Parser.hpp +// MediaPlayer +// +// Created by xzl on 2017/1/16. +// Copyright © 2017年 jizan. All rights reserved. +// + +#ifndef H264Parser_h +#define H264Parser_h + +#include +#include +#include "h264_parser.h" +#include "h264_poc.h" + +using namespace std; + + +class H264Parser{ +public: + H264Parser(); + virtual ~H264Parser(); + void inputH264(const string &h264,uint32_t dts); + + int32_t getPOC() const{ + return m_iNowPOC; + } + int getSliceType() const{ + return m_shdr.slice_type; + } + int getNaluType() const{ + return m_nalu.nal_unit_type; + } + uint32_t getPts() const{ + return m_iNowPTS; + } +private: + media::H264Parser m_parser; + media::H264POC m_poc; + media::H264NALU m_nalu; + media::H264SliceHeader m_shdr; + + int32_t m_iNowPOC = INT32_MAX; + int32_t m_iLastPOC = INT32_MAX; + + uint32_t m_iNowPTS = INT32_MAX; + uint32_t m_iLastPTS = INT32_MAX; + int32_t m_iMsPerPOC = 30; + + void computePts(uint32_t dts); + + +}; + +#endif /* H264Parser_hpp */ diff --git a/src/H264/SPSParser.c b/src/H264/SPSParser.c new file mode 100644 index 00000000..7fb534da --- /dev/null +++ b/src/H264/SPSParser.c @@ -0,0 +1,1039 @@ +#include +#include +#include +#include /* for uint32_t, etc */ +#include + +#include "SPSParser.h" + +/******************************************** +*define here +********************************************/ +#define SPS_PPS_DEBUG +//#undef SPS_PPS_DEBUG + + +#define MAX_LEN 32 +#define EXTENDED_SAR 255 +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#define MAX_SPS_COUNT 32 +#define MAX_LOG2_MAX_FRAME_NUM (12 + 4) +#define MIN_LOG2_MAX_FRAME_NUM 4 +#define H264_MAX_PICTURE_COUNT 36 +#define CODEC_FLAG2_IGNORE_CROP 0x00010000 ///< Discard cropping information from SPS. +#define INT_MAX 65535 + + +/* report level */ +#define RPT_ERR (1) // error, system error +#define RPT_WRN (2) // warning, maybe wrong, maybe OK +#define RPT_INF (3) // important information +#define RPT_DBG (4) // debug information + +static int rpt_lvl = RPT_WRN; /* report level: ERR, WRN, INF, DBG */ + +/* report micro */ +#define RPT(lvl, ...) \ + do { \ + if(lvl <= rpt_lvl) { \ + switch(lvl) { \ + case RPT_ERR: \ + fprintf(stderr, "\"%s\" line %d [err]: ", __FILE__, __LINE__); \ + break; \ + case RPT_WRN: \ + fprintf(stderr, "\"%s\" line %d [wrn]: ", __FILE__, __LINE__); \ + break; \ + case RPT_INF: \ + fprintf(stderr, "\"%s\" line %d [inf]: ", __FILE__, __LINE__); \ + break; \ + case RPT_DBG: \ + fprintf(stderr, "\"%s\" line %d [dbg]: ", __FILE__, __LINE__); \ + break; \ + default: \ + fprintf(stderr, "\"%s\" line %d [???]: ", __FILE__, __LINE__); \ + break; \ + } \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } while(0) + +static const uint8_t sg_aau8DefaultScaling4[2][16] = { + { 6, 13, 20, 28, 13, 20, 28, 32, + 20, 28, 32, 37, 28, 32, 37, 42 }, + { 10, 14, 20, 24, 14, 20, 24, 27, + 20, 24, 27, 30, 24, 27, 30, 34 } +}; + +static const uint8_t sg_aau8DefaultScaling8[2][64] = { + { 6, 10, 13, 16, 18, 23, 25, 27, + 10, 11, 16, 18, 23, 25, 27, 29, + 13, 16, 18, 23, 25, 27, 29, 31, + 16, 18, 23, 25, 27, 29, 31, 33, + 18, 23, 25, 27, 29, 31, 33, 36, + 23, 25, 27, 29, 31, 33, 36, 38, + 25, 27, 29, 31, 33, 36, 38, 40, + 27, 29, 31, 33, 36, 38, 40, 42 }, + { 9, 13, 15, 17, 19, 21, 22, 24, + 13, 13, 17, 19, 21, 22, 24, 25, + 15, 17, 19, 21, 22, 24, 25, 27, + 17, 19, 21, 22, 24, 25, 27, 28, + 19, 21, 22, 24, 25, 27, 28, 30, + 21, 22, 24, 25, 27, 28, 30, 32, + 22, 24, 25, 27, 28, 30, 32, 33, + 24, 25, 27, 28, 30, 32, 33, 35 } +}; + +static const T_AVRational sg_atFfH264PixelSspect[17] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +static const uint8_t sg_au8ZigzagScan[16+1] = { + 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, + 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, + 1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, + 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4, +}; + +const uint8_t g_au8FfZigzagDirect[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + + + +static inline int getBitsLeft(void *pvHandle) +{ + int iResLen = 0; + T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; + if(ptPtr->iBufSize <= 0 || ptPtr->iTotalBit <= 0) + { + RPT(RPT_WRN, "buffer size is zero"); + return 0; + } + + + iResLen = ptPtr->iTotalBit - ptPtr->iBitPos; + return iResLen; +} + + +/******************************************** +*functions +********************************************/ +/** + * @brief Function getOneBit() ¶Á1¸öbit + * @param[in] h T_GetBitContext structrue + * @retval 0: success, -1 : failure + * @pre + * @post + */ +static int getOneBit(void *pvHandle) +{ + T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; + int iRet = 0; + uint8_t *pu8CurChar = NULL; + uint8_t u8Shift; + int iResoLen = 0; + + if(NULL == ptPtr) + { + RPT(RPT_ERR, "NULL pointer"); + iRet = -1; + goto exit; + } + iResoLen = getBitsLeft(ptPtr); + if(iResoLen < 1) + { + iRet = -1; + goto exit; + } + + pu8CurChar = ptPtr->pu8Buf + (ptPtr->iBitPos >> 3); + u8Shift = 7 - (ptPtr->iCurBitPos); + ptPtr->iBitPos++; + ptPtr->iCurBitPos = ptPtr->iBitPos & 0x7; + iRet = ((*pu8CurChar) >> u8Shift) & 0x01; + +exit: + return iRet; +} + + +/** + * @brief Function getBits() ¶Án¸öbits£¬n²»Äܳ¬¹ý32 + * @param[in] h T_GetBitContext structrue + * @param[in] n how many bits you want? + * @retval 0: success, -1 : failure + * @pre + * @post + */ +static int getBits(void *pvHandle, int iN) +{ + T_GetBitContext *ptPtr = (T_GetBitContext *)pvHandle; + uint8_t au8Temp[5] = {0}; + uint8_t *pu8CurChar = NULL; + uint8_t u8Nbyte; + uint8_t u8Shift; + uint32_t u32Result = 0; + int iRet = 0; + int iResoLen = 0; + + if(NULL == ptPtr) + { + RPT(RPT_ERR, "NULL pointer"); + iRet = -1; + goto exit; + } + + if(iN > MAX_LEN) + { + iN = MAX_LEN; + } + + iResoLen = getBitsLeft(ptPtr); + if(iResoLen < iN) + { + iRet = -1; + goto exit; + } + + + if((ptPtr->iBitPos + iN) > ptPtr->iTotalBit) + { + iN = ptPtr->iTotalBit- ptPtr->iBitPos; + } + + pu8CurChar = ptPtr->pu8Buf+ (ptPtr->iBitPos>>3); + u8Nbyte = (ptPtr->iCurBitPos + iN + 7) >> 3; + u8Shift = (8 - (ptPtr->iCurBitPos + iN))& 0x07; + + if(iN == MAX_LEN) + { + RPT(RPT_DBG, "12(ptPtr->iBitPos(:%d) + iN(:%d)) > ptPtr->iTotalBit(:%d)!!! ",\ + ptPtr->iBitPos, iN, ptPtr->iTotalBit); + RPT(RPT_DBG, "0x%x 0x%x 0x%x 0x%x", (*pu8CurChar), *(pu8CurChar+1),*(pu8CurChar+2),*(pu8CurChar+3)); + } + + memcpy(&au8Temp[5-u8Nbyte], pu8CurChar, u8Nbyte); + iRet = (uint32_t)au8Temp[0] << 24; + iRet = iRet << 8; + iRet = ((uint32_t)au8Temp[1]<<24)|((uint32_t)au8Temp[2] << 16)\ + |((uint32_t)au8Temp[3] << 8)|au8Temp[4]; + + iRet = (iRet >> u8Shift) & (((uint64_t)1<iBitPos += iN; + ptPtr->iCurBitPos = ptPtr->iBitPos & 0x7; + +exit: + return u32Result; +} + + + +/** + * @brief Function parseCodenum() Ö¸Êý¸çÂײ¼±àÂë½âÎö£¬²Î¿¼h264±ê×¼µÚ9½Ú + * @param[in] buf + * @retval u32CodeNum + * @pre + * @post + */ +static int parseCodenum(void *pvBuf) +{ + uint8_t u8LeadingZeroBits = -1; + uint8_t u8B; + uint32_t u32CodeNum = 0; + + for(u8B=0; !u8B; u8LeadingZeroBits++) + { + u8B = getOneBit(pvBuf); + } + + u32CodeNum = ((uint32_t)1 << u8LeadingZeroBits) - 1 + getBits(pvBuf, u8LeadingZeroBits); + + return u32CodeNum; +} + +/** + * @brief Function parseUe() Ö¸Êý¸çÂײ¼±àÂë½âÎö ue(),²Î¿¼h264±ê×¼µÚ9½Ú + * @param[in] buf sps_pps parse buf + * @retval u32CodeNum + * @pre + * @post + */ +static int parseUe(void *pvBuf) +{ + return parseCodenum(pvBuf); +} + + +/** + * @brief Function parseSe() Ö¸Êý¸çÂײ¼±àÂë½âÎö se(), ²Î¿¼h264±ê×¼µÚ9½Ú + * @param[in] buf sps_pps parse buf + * @retval u32CodeNum + * @pre + * @post + */ +static int parseSe(void *pvBuf) +{ + int iRet = 0; + int u32CodeNum; + + u32CodeNum = parseCodenum(pvBuf); + iRet = (u32CodeNum + 1) >> 1; + iRet = (u32CodeNum & 0x01)? iRet : -iRet; + + return iRet; +} + + +/** + * @brief Function getBitContextFree() ÉêÇëµÄget_bit_context½á¹¹ÄÚ´æÊÍ·Å + * @param[in] buf T_GetBitContext buf + * @retval none + * @pre + * @post + */ +static void getBitContextFree(void *pvBuf) +{ + T_GetBitContext *ptPtr = (T_GetBitContext *)pvBuf; + + if(ptPtr) + { + if(ptPtr->pu8Buf) + { + free(ptPtr->pu8Buf); + } + + free(ptPtr); + } +} + + + + +/** + * @brief Function deEmulationPrevention() ½â¾ºÕù´úÂë + * @param[in] buf T_GetBitContext buf + * @retval none + * @pre + * @post + * @note: + * µ÷ÊÔʱ×ÜÊÇ·¢ÏÖvui.time_scaleÖµÌرðÆæ¹Ö£¬×ÜÊÇ16777216£¬ºóÀ´²éѯԭÒòÈçÏÂ: + * http://www.cnblogs.com/eustoma/archive/2012/02/13/2415764.html + * H.264±àÂëʱ£¬ÔÚÿ¸öNALÇ°Ìí¼ÓÆðʼÂë 0x000001£¬½âÂëÆ÷ÔÚÂëÁ÷Öмì²âµ½ÆðʼÂ룬µ±Ç°NAL½áÊø¡£ + * ΪÁË·ÀÖ¹NALÄÚ²¿³öÏÖ0x000001µÄÊý¾Ý£¬h.264ÓÖÌá³ö'·ÀÖ¹¾ºÕù emulation prevention"»úÖÆ£¬ + * ÔÚ±àÂëÍêÒ»¸öNALʱ£¬Èç¹û¼ì²â³öÓÐÁ¬ÐøÁ½¸ö0x00×Ö½Ú£¬¾ÍÔÚºóÃæ²åÈëÒ»¸ö0x03¡£ + * µ±½âÂëÆ÷ÔÚNALÄÚ²¿¼ì²âµ½0x000003µÄÊý¾Ý£¬¾Í°Ñ0x03Å×Æú£¬»Ö¸´Ô­Ê¼Êý¾Ý¡£ + * 0x000000 >>>>>> 0x00000300 + * 0x000001 >>>>>> 0x00000301 + * 0x000002 >>>>>> 0x00000302 + * 0x000003 >>>>>> 0x00000303 + */ +static void *deEmulationPrevention(void *pvBuf) +{ + T_GetBitContext *ptPtr = NULL; + T_GetBitContext *ptBufPtr = (T_GetBitContext *)pvBuf; + int i = 0, j = 0; + uint8_t *pu8TmpPtr = NULL; + int tmp_buf_size = 0; + int iVal = 0; + + if(NULL == ptBufPtr) + { + RPT(RPT_ERR, "NULL ptPtr"); + goto exit; + } + + ptPtr = (T_GetBitContext *)malloc(sizeof(T_GetBitContext)); + if(NULL == ptPtr) + { + RPT(RPT_ERR, "NULL ptPtr"); + goto exit; + } + + memcpy(ptPtr, ptBufPtr, sizeof(T_GetBitContext)); + + ptPtr->pu8Buf = (uint8_t *)malloc(ptPtr->iBufSize); + if(NULL == ptPtr->pu8Buf) + { + RPT(RPT_ERR, "NULL ptPtr"); + goto exit; + } + + memcpy(ptPtr->pu8Buf, ptBufPtr->pu8Buf, ptBufPtr->iBufSize); + + pu8TmpPtr = ptPtr->pu8Buf; + tmp_buf_size = ptPtr->iBufSize; + for(i=0; i<(tmp_buf_size-2); i++) + { + /*¼ì²â0x000003*/ + iVal = (pu8TmpPtr[i]^0x00) + (pu8TmpPtr[i+1]^0x00) + (pu8TmpPtr[i+2]^0x03); + if(iVal == 0) + { + /*ÌÞ³ý0x03*/ + for(j=i+2; jiBufSize--; + } + } + + /*ÖØмÆËãtotal_bit*/ + ptPtr->iTotalBit = ptPtr->iBufSize << 3; + + return (void *)ptPtr; + +exit: + getBitContextFree(ptPtr); + return NULL; +} + +static void decodeScalingList(void *pvBuf, uint8_t *pu8Factors, int iSize, + const uint8_t *pu8JvtList, + const uint8_t *pu8FallbackList) +{ + int i; + int iLast = 8; + int iNext = 8; + const uint8_t *pu8Scan = iSize == 16 ? sg_au8ZigzagScan : g_au8FfZigzagDirect; + + if (!getOneBit(pvBuf)) /* matrix not written, we use the predicted one */ + memcpy(pu8Factors, pu8FallbackList, iSize * sizeof(uint8_t)); + else + for (i = 0; i < iSize; i++) + { + if (iNext) + { + + iNext = (iLast + parseSe(pvBuf)) & 0xff; + } + if (!i && !iNext) + { + /* matrix not written, we use the preset one */ + memcpy(pu8Factors, pu8JvtList, iSize * sizeof(uint8_t)); + break; + } + iLast = pu8Factors[pu8Scan[i]] = iNext ? iNext : iLast; + } +} + + + int decodeScalingMatrices(void *pvBuf, T_SPS *ptSps, + T_PPS *ptPps, int iIsSps, + uint8_t(*pau8ScalingMatrix4)[16], + uint8_t(*pau8ScalingMatrix8)[64]) +{ + int iFallbackSps = !iIsSps && ptSps->iScalingMatrixPresent; + const uint8_t *pau8Fallback[4] = { + iFallbackSps ? ptSps->aau8ScalingMatrix4[0] : sg_aau8DefaultScaling4[0], + iFallbackSps ? ptSps->aau8ScalingMatrix4[3] : sg_aau8DefaultScaling4[1], + iFallbackSps ? ptSps->aau8ScalingMatrix8[0] : sg_aau8DefaultScaling8[0], + iFallbackSps ? ptSps->aau8ScalingMatrix8[3] : sg_aau8DefaultScaling8[1] + }; + if (getOneBit(pvBuf)) { + ptSps->iScalingMatrixPresent |= iIsSps; + decodeScalingList(pvBuf, pau8ScalingMatrix4[0], 16, sg_aau8DefaultScaling4[0], pau8Fallback[0]); // Intra, Y + decodeScalingList(pvBuf, pau8ScalingMatrix4[1], 16, sg_aau8DefaultScaling4[0], pau8ScalingMatrix4[0]); // Intra, Cr + decodeScalingList(pvBuf, pau8ScalingMatrix4[2], 16, sg_aau8DefaultScaling4[0], pau8ScalingMatrix4[1]); // Intra, Cb + + decodeScalingList(pvBuf, pau8ScalingMatrix4[3], 16, sg_aau8DefaultScaling4[1], pau8Fallback[1]); // Inter, Y + + decodeScalingList(pvBuf, pau8ScalingMatrix4[4], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[3]); // Inter, Cr + + decodeScalingList(pvBuf, pau8ScalingMatrix4[5], 16, sg_aau8DefaultScaling4[1], pau8ScalingMatrix4[4]); // Inter, Cb + + + if (iIsSps || ptPps->iTransform8x8Mode) + { + decodeScalingList(pvBuf, pau8ScalingMatrix8[0], 64, sg_aau8DefaultScaling8[0], pau8Fallback[2]); // Intra, Y + decodeScalingList(pvBuf, pau8ScalingMatrix8[3], 64, sg_aau8DefaultScaling8[1], pau8Fallback[3]); // Inter, Y + if (ptSps->iChromaFormatIdc == 3) { + decodeScalingList(pvBuf, pau8ScalingMatrix8[1], 64, sg_aau8DefaultScaling8[0], pau8ScalingMatrix8[0]); // Intra, Cr + decodeScalingList(pvBuf, pau8ScalingMatrix8[4], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[3]); // Inter, Cr + decodeScalingList(pvBuf, pau8ScalingMatrix8[2], 64, sg_aau8DefaultScaling8[0], pau8ScalingMatrix8[1]); // Intra, Cb + decodeScalingList(pvBuf, pau8ScalingMatrix8[5], 64, sg_aau8DefaultScaling8[1], pau8ScalingMatrix8[4]); // Inter, Cb + } + } + } + return 0; +} + +static int decodeHrdPAarameters(void *pvBuf, T_SPS *ptSps) +{ + int iCpbCount = 0; + int i; + iCpbCount = parseUe(pvBuf); + + if (iCpbCount > 32U) + { + RPT(RPT_ERR,"iCpbCount %d invalid\n", iCpbCount); + return -1; + + } + + getBits(pvBuf, 4); /* bit_rate_scale */ + getBits(pvBuf, 4); /* cpb_size_scale */ + for (i = 0; i < iCpbCount; i++) + { + parseUe(pvBuf); + parseUe(pvBuf); + //get_ue_golomb_long(&h->gb); /* bit_rate_value_minus1 */ + //get_ue_golomb_long(&h->gb); /* cpb_size_value_minus1 */ + getOneBit(pvBuf); /* cbr_flag */ + } + ptSps->iInitialCpbRemovalDelayLength = getBits(pvBuf, 5) + 1; + ptSps->iCpbRemovalDelayLength = getBits(pvBuf, 5) + 1; + ptSps->iDpbOutputDelayLength = getBits(pvBuf, 5) + 1; + ptSps->iTimeOffsetLength = getBits(pvBuf, 5); + ptSps->iCpbCnt = iCpbCount; + return 0; +} + + +static inline int decodeVuiParameters(void *pvBuf, T_SPS *ptSps) +{ + int iAspectRatioInfoPresentFlag; + unsigned int uiAspectRatioIdc; + int iChromaSampleLocation; + + iAspectRatioInfoPresentFlag = getOneBit(pvBuf); + + if (iAspectRatioInfoPresentFlag) { + uiAspectRatioIdc = getBits(pvBuf, 8); + if (uiAspectRatioIdc == EXTENDED_SAR) { + ptSps->tSar.num = getBits(pvBuf, 16); + ptSps->tSar.den = getBits(pvBuf, 16); + } else if (uiAspectRatioIdc < FF_ARRAY_ELEMS(sg_atFfH264PixelSspect)) { + ptSps->tSar = sg_atFfH264PixelSspect[uiAspectRatioIdc]; + } else + { + RPT(RPT_ERR,"illegal aspect ratio\n"); + return -1; + } + } else + { + ptSps->tSar.num = + ptSps->tSar.den = 0; + } + + if (getOneBit(pvBuf)) /* overscan_info_present_flag */ + getOneBit(pvBuf); /* overscan_appropriate_flag */ + + ptSps->iVideoSignalTypePresentFlag = getOneBit(pvBuf); + if (ptSps->iVideoSignalTypePresentFlag) { + getBits(pvBuf, 3); /* video_format */ + ptSps->iFullRange = getOneBit(pvBuf); /* video_full_range_flag */ + + ptSps->iColourDescriptionPresentFlag = getOneBit(pvBuf); + if (ptSps->iColourDescriptionPresentFlag) { + ptSps->tColorPrimaries = getBits(pvBuf, 8); /* colour_primaries */ + ptSps->tColorTrc = getBits(pvBuf, 8); /* transfer_characteristics */ + ptSps->tColorspace = getBits(pvBuf, 8); /* matrix_coefficients */ + if (ptSps->tColorPrimaries >= AVCOL_PRI_NB) + ptSps->tColorPrimaries = AVCOL_PRI_UNSPECIFIED; + if (ptSps->tColorTrc >= AVCOL_TRC_NB) + ptSps->tColorTrc = AVCOL_TRC_UNSPECIFIED; + if (ptSps->tColorspace >= AVCOL_SPC_NB) + ptSps->tColorspace = AVCOL_SPC_UNSPECIFIED; + } + } + + /* chroma_location_info_present_flag */ + if (getOneBit(pvBuf)) + { + /* chroma_sample_location_type_top_field */ + iChromaSampleLocation = parseUe(pvBuf); + parseUe(pvBuf); /* chroma_sample_location_type_bottom_field */ + } + if(getBitsLeft(pvBuf) < 10) + { + return 0; + } + + + ptSps->iTimingInfoPresentFlag = getOneBit(pvBuf); + if (ptSps->iTimingInfoPresentFlag) { + unsigned u32NumUnitsInTick = getBits(pvBuf, 32); + unsigned u32TimeScale = getBits(pvBuf, 32); + if (!u32NumUnitsInTick || !u32TimeScale) { + + RPT(RPT_ERR,"u32TimeScale/u32NumUnitsInTick invalid or unsupported (%u/%u)\n",u32TimeScale, u32NumUnitsInTick); + ptSps->iTimingInfoPresentFlag = 0; + } else { + ptSps->u32NumUnitsInTick = u32NumUnitsInTick; + ptSps->u32TimeScale = u32TimeScale; + } + ptSps->iFixedFrameRateFlag = getOneBit(pvBuf); + } + + ptSps->iNalHrdParametersPresentFlag = getOneBit(pvBuf); + if (ptSps->iNalHrdParametersPresentFlag) + if (decodeHrdPAarameters(pvBuf, ptSps) < 0) + return -1; + ptSps->iVclHrdParametersPresentFlag = getOneBit(pvBuf); + if (ptSps->iVclHrdParametersPresentFlag) + if (decodeHrdPAarameters(pvBuf, ptSps) < 0) + return -1; + if (ptSps->iNalHrdParametersPresentFlag || + ptSps->iVclHrdParametersPresentFlag) + getOneBit(pvBuf); /* low_delay_hrd_flag */ + ptSps->iPicStructPresentFlag = getOneBit(pvBuf); + + if(getBitsLeft(pvBuf) == 0) + return 0; + ptSps->iBitstreamRestrictionFlag = getOneBit(pvBuf); + if (ptSps->iBitstreamRestrictionFlag) { + getOneBit(pvBuf); /* motion_vectors_over_pic_boundaries_flag */ + parseUe(pvBuf); + //get_ue_golomb(&h->gb); /* max_bytes_per_pic_denom */ + parseUe(pvBuf); + //get_ue_golomb(&h->gb); /* max_bits_per_mb_denom */ + parseUe(pvBuf); + //get_ue_golomb(&h->gb); /* log2_max_mv_length_horizontal */ + parseUe(pvBuf); + //get_ue_golomb(&h->gb); /* log2_max_mv_length_vertical */ + ptSps->iNumReorderFrames = parseUe(pvBuf); + + parseUe(pvBuf); + //get_ue_golomb(&h->gb); /*max_dec_frame_buffering*/ + + if (getBitsLeft(pvBuf) < 0) + { + ptSps->iNumReorderFrames = 0; + ptSps->iBitstreamRestrictionFlag = 0; + } + + if (ptSps->iNumReorderFrames > 16U + /* max_dec_frame_buffering || max_dec_frame_buffering > 16 */) + { + RPT(RPT_ERR, "Clipping illegal iNumReorderFrames %d\n", + ptSps->iNumReorderFrames); + ptSps->iNumReorderFrames = 16; + return -1; + } + } + + return 0; +} + + +int h264DecSeqParameterSet(void *pvBufSrc, T_SPS *ptSps) +{ + int iLevelIdc; + int iConstraintSetFlags = 0; + unsigned int uiSpsId; + int i; + int iLog2MaxFrameNumMinus4; + + int iRet = 0; + int iProfileIdc = 0; + void *pvBuf = NULL; + + + + if(NULL == pvBufSrc || NULL == ptSps) + { + RPT(RPT_ERR,"ERR null pointer\n"); + iRet = -1; + goto exit; + } + + memset((void *)ptSps, 0, sizeof(T_SPS)); + + pvBuf = deEmulationPrevention(pvBufSrc); + if(NULL == pvBuf) + { + RPT(RPT_ERR,"ERR null pointer\n"); + iRet = -1; + goto exit; + } + + iProfileIdc = getBits(pvBuf, 8); + iConstraintSetFlags |= getOneBit(pvBuf) << 0; // constraint_set0_flag + iConstraintSetFlags |= getOneBit(pvBuf) << 1; // constraint_set1_flag + iConstraintSetFlags |= getOneBit(pvBuf) << 2; // constraint_set2_flag + iConstraintSetFlags |= getOneBit(pvBuf) << 3; // constraint_set3_flag + iConstraintSetFlags |= getOneBit(pvBuf) << 4; // constraint_set4_flag + iConstraintSetFlags |= getOneBit(pvBuf) << 5; // constraint_set5_flag + getBits(pvBuf, 2); // reserved_zero_2bits + iLevelIdc = getBits(pvBuf, 8); + uiSpsId = parseUe(pvBuf); + + if (uiSpsId >= MAX_SPS_COUNT) { + RPT(RPT_ERR, "uiSpsId %u out of range\n", uiSpsId); + iRet = -1; + goto exit; + + } + + + ptSps->uiSpsId = uiSpsId; + ptSps->iTimeOffsetLength = 24; + ptSps->iProfileIdc = iProfileIdc; + ptSps->iConstraintSetFlags = iConstraintSetFlags; + ptSps->iLevelIdc = iLevelIdc; + ptSps->iFullRange = -1; + + memset(ptSps->aau8ScalingMatrix4, 16, sizeof(ptSps->aau8ScalingMatrix4)); + memset(ptSps->aau8ScalingMatrix8, 16, sizeof(ptSps->aau8ScalingMatrix8)); + ptSps->iScalingMatrixPresent = 0; + ptSps->tColorspace = 2; //AVCOL_SPC_UNSPECIFIED + + if (ptSps->iProfileIdc == 100 || // High profile + ptSps->iProfileIdc == 110 || // High10 profile + ptSps->iProfileIdc == 122 || // High422 profile + ptSps->iProfileIdc == 244 || // High444 Predictive profile + ptSps->iProfileIdc == 44 || // Cavlc444 profile + ptSps->iProfileIdc == 83 || // Scalable Constrained High profile (SVC) + ptSps->iProfileIdc == 86 || // Scalable High Intra profile (SVC) + ptSps->iProfileIdc == 118 || // Stereo High profile (MVC) + ptSps->iProfileIdc == 128 || // Multiview High profile (MVC) + ptSps->iProfileIdc == 138 || // Multiview Depth High profile (MVCD) + ptSps->iProfileIdc == 144) { // old High444 profile + ptSps->iChromaFormatIdc = parseUe(pvBuf); + if (ptSps->iChromaFormatIdc > 3U) + { + RPT(RPT_ERR, "iChromaFormatIdc %u",ptSps->iChromaFormatIdc); + iRet = -1; + goto exit; + } + else if (ptSps->iChromaFormatIdc == 3) + { + ptSps->iResidualColorTransformFlag = getOneBit(pvBuf); + if (ptSps->iResidualColorTransformFlag) + { + RPT(RPT_ERR, "separate color planes are not supported\n"); + iRet = -1; + goto exit; + + } + } + ptSps->iBitDepthLuma = parseUe(pvBuf) + 8; + ptSps->iBitDepthChroma = parseUe(pvBuf) + 8; + if (ptSps->iBitDepthChroma != ptSps->iBitDepthLuma) + { + RPT(RPT_ERR, "Different chroma and luma bit depth"); + iRet = -1; + goto exit; + + } + if (ptSps->iBitDepthLuma < 8 || ptSps->iBitDepthLuma > 14 || + ptSps->iBitDepthChroma < 8 || ptSps->iBitDepthChroma > 14) + { + RPT(RPT_ERR, "illegal bit depth value (%d, %d)\n",ptSps->iBitDepthLuma, ptSps->iBitDepthChroma); + iRet = -1; + goto exit; + } + ptSps->iTransformBypass = getOneBit(pvBuf); + decodeScalingMatrices(pvBuf, ptSps, NULL, 1, + ptSps->aau8ScalingMatrix4, ptSps->aau8ScalingMatrix8); + } + else + { + + ptSps->iChromaFormatIdc = 1; + ptSps->iBitDepthLuma = 8; + ptSps->iBitDepthChroma = 8; + } + + iLog2MaxFrameNumMinus4 = parseUe(pvBuf); + + if (iLog2MaxFrameNumMinus4 < MIN_LOG2_MAX_FRAME_NUM - 4 || + iLog2MaxFrameNumMinus4 > MAX_LOG2_MAX_FRAME_NUM - 4) + { + RPT(RPT_ERR, "iLog2MaxFrameNumMinus4 out of range (0-12): %d\n", iLog2MaxFrameNumMinus4); + iRet = -1; + goto exit; + + } + ptSps->iLog2MaxFrameNum = iLog2MaxFrameNumMinus4 + 4; + + ptSps->iPocType = parseUe(pvBuf); + + if (ptSps->iPocType == 0) + { + // FIXME #define + unsigned t = parseUe(pvBuf); + if (t>12) + { + RPT(RPT_ERR, "iLog2MaxPocLsb (%d) is out of range\n", t); + iRet = -1; + goto exit; + + } + ptSps->iLog2MaxPocLsb = t + 4; + } + else if (ptSps->iPocType == 1) + { + // FIXME #define + ptSps->iDeltaPicOrderAlwaysZeroFlag = getOneBit(pvBuf); + ptSps->iOffsetForNonRefPic = parseSe(pvBuf); + ptSps->iOffsetForTopToBottomField = parseSe(pvBuf); + ptSps->iPocCycleLength = parseUe(pvBuf); + + if ((unsigned)ptSps->iPocCycleLength >= FF_ARRAY_ELEMS(ptSps->asOffsetForRefFrame)) + { + RPT(RPT_ERR, "iPocCycleLength overflow %d\n", ptSps->iPocCycleLength); + iRet = -1; + goto exit; + + } + + for (i = 0; i < ptSps->iPocCycleLength; i++) + ptSps->asOffsetForRefFrame[i] = parseSe(pvBuf); + } + else if (ptSps->iPocType != 2) + { + RPT(RPT_ERR, "illegal POC type %d\n", ptSps->iPocType); + iRet = -1; + goto exit; + + } + + ptSps->iRefFrameCount = parseUe(pvBuf); + if (ptSps->iRefFrameCount > H264_MAX_PICTURE_COUNT - 2 || + ptSps->iRefFrameCount > 16U) + { + RPT(RPT_ERR, "too many reference frames %d\n", ptSps->iRefFrameCount); + iRet = -1; + goto exit; + + } + ptSps->iGapsInFrameNumAllowedFlag = getOneBit(pvBuf); + ptSps->iMbWidth = parseUe(pvBuf) + 1; + ptSps->iMbHeight = parseUe(pvBuf) + 1; + + + ptSps->iFrameMbsOnlyFlag = getOneBit(pvBuf); + if (!ptSps->iFrameMbsOnlyFlag) + ptSps->iMbAff = getOneBit(pvBuf); + else + ptSps->iMbAff = 0; + + ptSps->iDirect8x8InferenceFlag = getOneBit(pvBuf); + + ptSps->iCrop = getOneBit(pvBuf); + if (ptSps->iCrop) { + unsigned int uiCropLeft = parseUe(pvBuf); + unsigned int uiCropRight = parseUe(pvBuf); + unsigned int uiCropTop = parseUe(pvBuf); + unsigned int uiCropBottom = parseUe(pvBuf); + int width = 16 * ptSps->iMbWidth; + int height = 16 * ptSps->iMbHeight * (2 - ptSps->iFrameMbsOnlyFlag); + + if(1) + { + int vsub = (ptSps->iChromaFormatIdc == 1) ? 1 : 0; + int hsub = (ptSps->iChromaFormatIdc == 1 || + ptSps->iChromaFormatIdc == 2) ? 1 : 0; + int step_x = 1 << hsub; + int step_y = (2 - ptSps->iFrameMbsOnlyFlag) << vsub; + + if (uiCropLeft & (0x1F >> (ptSps->iBitDepthLuma > 8))) + { + uiCropLeft &= ~(0x1F >> (ptSps->iBitDepthLuma > 8)); + } + + if (uiCropLeft > (unsigned)INT_MAX / 4 / step_x || + uiCropRight > (unsigned)INT_MAX / 4 / step_x || + uiCropTop > (unsigned)INT_MAX / 4 / step_y || + uiCropBottom> (unsigned)INT_MAX / 4 / step_y || + (uiCropLeft + uiCropRight ) * step_x >= width || + (uiCropTop + uiCropBottom) * step_y >= height + ) + { + RPT(RPT_ERR, "crop values invalid %d %d %d %d / %d %d\n", uiCropLeft, uiCropRight, uiCropTop, uiCropBottom, width, height); + iRet = -1; + goto exit; + } + + ptSps->uiCropLeft = uiCropLeft * step_x; + ptSps->uiCropRight = uiCropRight * step_x; + ptSps->uiCropTop = uiCropTop * step_y; + ptSps->uiCropBottom = uiCropBottom * step_y; + } + } + else + { + ptSps->uiCropLeft = + ptSps->uiCropRight = + ptSps->uiCropTop = + ptSps->uiCropBottom = + ptSps->iCrop = 0; + } + + ptSps->iVuiParametersPresentFlag = getOneBit(pvBuf); + if (ptSps->iVuiParametersPresentFlag) { + int ret = decodeVuiParameters(pvBuf, ptSps); + if (ret < 0) + goto exit; + } + + if (getBitsLeft(pvBuf) < 0) + { + RPT(RPT_ERR, "Overread %s by %d bits\n", ptSps->iVuiParametersPresentFlag ? "VUI" : "SPS", -getBitsLeft(pvBuf)); + iRet = -1; + } + + if (!ptSps->tSar.den) + ptSps->tSar.den = 1; + + ptSps->iNew = 1; + +exit: +#ifdef SPS_PPS_DEBUG + + if (1) + { + static const char csp[4][5] = { "Gray", "420", "422", "444" }; + RPT(RPT_DBG, + "ptSps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %d/%d b%d reo:%d\n", + uiSpsId, ptSps->iProfileIdc, ptSps->iLevelIdc, + ptSps->iPocType, + ptSps->iRefFrameCount, + ptSps->iMbWidth, ptSps->iMbHeight, + ptSps->iFrameMbsOnlyFlag ? "FRM" : (ptSps->iMbAff ? "MB-AFF" : "PIC-AFF"), + ptSps->iDirect8x8InferenceFlag ? "8B8" : "", + ptSps->uiCropLeft, ptSps->uiCropRight, + ptSps->uiCropTop, ptSps->uiCropBottom, + ptSps->iVuiParametersPresentFlag ? "VUI" : "", + csp[ptSps->iChromaFormatIdc], + ptSps->iTimingInfoPresentFlag ? ptSps->u32NumUnitsInTick : 0, + ptSps->iTimingInfoPresentFlag ? ptSps->u32TimeScale : 0, + ptSps->iBitDepthLuma, + ptSps->iBitstreamRestrictionFlag ? ptSps->iNumReorderFrames : -1 + ); + } + +#endif + getBitContextFree(pvBuf); + + return iRet; +} + +void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight) +{ + // ¿í¸ß¼ÆË㹫ʽ + int iCodeWidth = 0; + int iCodedHeight = 0; + iCodeWidth = 16 * ptSps->iMbWidth; + iCodedHeight = 16 * ptSps->iMbHeight; + *piWidth = iCodeWidth - (ptSps->uiCropRight + ptSps->uiCropLeft); + *piHeight = iCodedHeight - (ptSps->uiCropTop + ptSps->uiCropBottom); + if (*piWidth <= 0 || *piHeight <= 0) { + *piWidth = iCodeWidth; + *piHeight = iCodedHeight; + } + + RPT(RPT_DBG, "iCodeWidth:%d, iCodedHeight:%d\n", iCodeWidth, iCodedHeight); + + RPT(RPT_DBG, "*piWidth:%d, *piHeight:%d\n", *piWidth, *piHeight); + + RPT(RPT_DBG, "ptSps->uiCropRight:%d, ptSps->uiCropLeft:%d\n", ptSps->uiCropRight, ptSps->uiCropLeft); + + RPT(RPT_DBG, "ptSps->uiCropTop:%d, ptSps->uiCropBottom:%d\n", ptSps->uiCropTop, ptSps->uiCropBottom); + +} + +int h264GetFormat(T_SPS *ptSps) +{ + return ptSps->iFrameMbsOnlyFlag; +} + + +void h264GeFramerate(T_SPS *ptSps, float *pfFramerate) +{ + int iFrInt = 0; + if(ptSps->iTimingInfoPresentFlag) + { + if(!ptSps->iFixedFrameRateFlag) + { + *pfFramerate = (float)ptSps->u32TimeScale / (float)ptSps->u32NumUnitsInTick; + //iFrInt = ptSps->vui_parameters.u32TimeScale / ptSps->vui_parameters.u32NumUnitsInTick; + }else + { + *pfFramerate = (float)ptSps->u32TimeScale / (float)ptSps->u32NumUnitsInTick / 2.0; + //iFrInt = ptSps->vui_parameters.u32TimeScale / ptSps->vui_parameters.u32NumUnitsInTick / 2; + } + iFrInt = ptSps->u32TimeScale / ptSps->u32NumUnitsInTick / 2; + } + switch(iFrInt) + { + case 23:// 23.98 + RPT(RPT_DBG, "frame rate:23.98"); + break; + case 24: + RPT(RPT_DBG, "frame rate:24"); + break; + case 25: + RPT(RPT_DBG, "frame rate:25"); + break; + case 29://29.97 + RPT(RPT_DBG, "frame rate:29.97"); + break; + case 30: + RPT(RPT_DBG, "frame rate:30"); + break; + case 50: + RPT(RPT_DBG, "frame rate:50"); + break; + case 59://59.94 + RPT(RPT_DBG, "frame rate:59.94"); + break; + case 60: + RPT(RPT_DBG, "frame rate:60"); + break; + case 6: + RPT(RPT_DBG, "frame rate:6"); + break; + case 8: + RPT(RPT_DBG, "frame rate:8"); + break; + case 12: + RPT(RPT_DBG, "frame rate:12"); + break; + case 15: + RPT(RPT_DBG, "frame rate:15"); + break; + case 10: + RPT(RPT_DBG, "frame rate:10"); + break; + + default: + RPT(RPT_DBG, "frame rate:0"); + break; + } + + return; +} + + + diff --git a/src/H264/SPSParser.h b/src/H264/SPSParser.h new file mode 100644 index 00000000..29972f2b --- /dev/null +++ b/src/H264/SPSParser.h @@ -0,0 +1,192 @@ +/*************************************************************************************** + ***************************************************************************************/ +#ifndef _JZAN_SPS_PPS_H_ +#define _JZAN_SPS_PPS_H_ + +#if defined (__cplusplus) + extern "C" { +#endif + +#define QP_MAX_NUM (51 + 6*6) // The maximum supported qp + +/** + * Chromaticity coordinates of the source primaries. + */ +enum T_AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_NB, ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + */ +enum T_AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10 bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12 bit system + AVCOL_TRC_NB, ///< Not part of ABI +}; + +/** + * YUV tColorspace type. + */ +enum T_AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above + AVCOL_SPC_SMPTE240M = 7, + AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_NB, ///< Not part of ABI +}; + + +/** + * rational number numerator/denominator + */ +typedef struct T_AVRational{ + int num; ///< numerator + int den; ///< denominator +} T_AVRational; + + +/*** + * Sequence parameter set + * ¿É²Î¿¼H264±ê×¼µÚ7½ÚºÍ¸½Â¼D E + */ +#define Extended_SAR 255 + +/** + * Sequence parameter set + */ +typedef struct T_SPS { + unsigned int uiSpsId; + int iProfileIdc; + int iLevelIdc; + int iChromaFormatIdc; + int iTransformBypass; ///< qpprime_y_zero_transform_bypass_flag + int iLog2MaxFrameNum; ///< log2_max_frame_num_minus4 + 4 + int iPocType; ///< pic_order_cnt_type + int iLog2MaxPocLsb; ///< log2_max_pic_order_cnt_lsb_minus4 + int iDeltaPicOrderAlwaysZeroFlag; + int iOffsetForNonRefPic; + int iOffsetForTopToBottomField; + int iPocCycleLength; ///< num_ref_frames_in_pic_order_cnt_cycle + int iRefFrameCount; ///< num_ref_frames + int iGapsInFrameNumAllowedFlag; + int iMbWidth; ///< pic_width_in_mbs_minus1 + 1 + int iMbHeight; ///< pic_height_in_map_units_minus1 + 1 + int iFrameMbsOnlyFlag; + int iMbAff; ///< mb_adaptive_frame_field_flag + int iDirect8x8InferenceFlag; + int iCrop; ///< frame_cropping_flag + + /* those 4 are already in luma samples */ + unsigned int uiCropLeft; ///< frame_cropping_rect_left_offset + unsigned int uiCropRight; ///< frame_cropping_rect_right_offset + unsigned int uiCropTop; ///< frame_cropping_rect_top_offset + unsigned int uiCropBottom; ///< frame_cropping_rect_bottom_offset + int iVuiParametersPresentFlag; + T_AVRational tSar; + int iVideoSignalTypePresentFlag; + int iFullRange; + int iColourDescriptionPresentFlag; + enum T_AVColorPrimaries tColorPrimaries; + enum T_AVColorTransferCharacteristic tColorTrc; + enum T_AVColorSpace tColorspace; + int iTimingInfoPresentFlag; + uint32_t u32NumUnitsInTick; + uint32_t u32TimeScale; + int iFixedFrameRateFlag; + short asOffsetForRefFrame[256]; // FIXME dyn aloc? + int iBitstreamRestrictionFlag; + int iNumReorderFrames; + int iScalingMatrixPresent; + uint8_t aau8ScalingMatrix4[6][16]; + uint8_t aau8ScalingMatrix8[6][64]; + int iNalHrdParametersPresentFlag; + int iVclHrdParametersPresentFlag; + int iPicStructPresentFlag; + int iTimeOffsetLength; + int iCpbCnt; ///< See H.264 E.1.2 + int iInitialCpbRemovalDelayLength; ///< initial_cpb_removal_delay_length_minus1 + 1 + int iCpbRemovalDelayLength; ///< cpb_removal_delay_length_minus1 + 1 + int iDpbOutputDelayLength; ///< dpb_output_delay_length_minus1 + 1 + int iBitDepthLuma; ///< bit_depth_luma_minus8 + 8 + int iBitDepthChroma; ///< bit_depth_chroma_minus8 + 8 + int iResidualColorTransformFlag; ///< residual_colour_transform_flag + int iConstraintSetFlags; ///< constraint_set[0-3]_flag + int iNew; ///< flag to keep track if the decoder context needs re-init due to changed SPS +} T_SPS; + +/** + * Picture parameter set + */ +typedef struct T_PPS { + unsigned int uiSpsId; + int iCabac; ///< entropy_coding_mode_flag + int iPicOrderPresent; ///< pic_order_present_flag + int iSliceGroupCount; ///< num_slice_groups_minus1 + 1 + int iMbSliceGroupMapType; + unsigned int auiRefCount[2]; ///< num_ref_idx_l0/1_active_minus1 + 1 + int iWeightedPred; ///< weighted_pred_flag + int iWeightedBipredIdc; + int iInitQp; ///< pic_init_qp_minus26 + 26 + int iInitQs; ///< pic_init_qs_minus26 + 26 + int aiChromaQpIndexOffset[2]; + int iDeblockingFilterParametersPresent; ///< deblocking_filter_parameters_present_flag + int iConstrainedIntraPred; ///< constrained_intra_pred_flag + int iRedundantPicCntPresent; ///< redundant_pic_cnt_present_flag + int iTransform8x8Mode; ///< transform_8x8_mode_flag + uint8_t aau8ScalingMatrix4[6][16]; + uint8_t aau8ScalingMatrix8[6][64]; + uint8_t u8ChromaQpTable[2][QP_MAX_NUM+1]; ///< pre-scaled (with aiChromaQpIndexOffset) version of qp_table + int iChromaQpDiff; +} T_PPS; + +typedef struct T_GetBitContext{ + uint8_t *pu8Buf; /*Ö¸ÏòSPS start*/ + int iBufSize; /*SPS ³¤¶È*/ + int iBitPos; /*bitÒѶÁȡλÖÃ*/ + int iTotalBit; /*bit×ܳ¤¶È*/ + int iCurBitPos; /*µ±Ç°¶ÁȡλÖÃ*/ +}T_GetBitContext; + + +int h264DecSeqParameterSet(void *pvBuf, T_SPS *ptSps); +void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight); +void h264GeFramerate(T_SPS *ptSps, float *pfFramerate); + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/H264/h264_bit_reader.cpp b/src/H264/h264_bit_reader.cpp new file mode 100644 index 00000000..92b3ac3d --- /dev/null +++ b/src/H264/h264_bit_reader.cpp @@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "h264_bit_reader.h" +#include "macros.h" +namespace media { + + H264BitReader::H264BitReader() + : data_(NULL), + bytes_left_(0), + curr_byte_(0), + num_remaining_bits_in_curr_byte_(0), + prev_two_bytes_(0), + emulation_prevention_bytes_(0) {} + + H264BitReader::~H264BitReader() {} + + bool H264BitReader::Initialize(const uint8_t* data, off_t size) { + DCHECK(data); + + if (size < 1) + return false; + + data_ = data; + bytes_left_ = size; + num_remaining_bits_in_curr_byte_ = 0; + // Initially set to 0xffff to accept all initial two-byte sequences. + prev_two_bytes_ = 0xffff; + emulation_prevention_bytes_ = 0; + + return true; + } + + bool H264BitReader::UpdateCurrByte() { + if (bytes_left_ < 1) + return false; + + // Emulation prevention three-byte detection. + // If a sequence of 0x000003 is found, skip (ignore) the last byte (0x03). + if (*data_ == 0x03 && (prev_two_bytes_ & 0xffff) == 0) { + // Detected 0x000003, skip last byte. + ++data_; + --bytes_left_; + ++emulation_prevention_bytes_; + // Need another full three bytes before we can detect the sequence again. + prev_two_bytes_ = 0xffff; + + if (bytes_left_ < 1) + return false; + } + + // Load a new byte and advance pointers. + curr_byte_ = *data_++ & 0xff; + --bytes_left_; + num_remaining_bits_in_curr_byte_ = 8; + + prev_two_bytes_ = ((prev_two_bytes_ & 0xff) << 8) | curr_byte_; + + return true; + } + + // Read |num_bits| (1 to 31 inclusive) from the stream and return them + // in |out|, with first bit in the stream as MSB in |out| at position + // (|num_bits| - 1). + bool H264BitReader::ReadBits(int num_bits, int* out) { + int bits_left = num_bits; + *out = 0; + DCHECK(num_bits <= 31); + + while (num_remaining_bits_in_curr_byte_ < bits_left) { + // Take all that's left in current byte, shift to make space for the rest. + *out |= (curr_byte_ << (bits_left - num_remaining_bits_in_curr_byte_)); + bits_left -= num_remaining_bits_in_curr_byte_; + + if (!UpdateCurrByte()) + return false; + } + + *out |= (curr_byte_ >> (num_remaining_bits_in_curr_byte_ - bits_left)); + *out &= ((1u << num_bits) - 1u); + num_remaining_bits_in_curr_byte_ -= bits_left; + + return true; + } + + off_t H264BitReader::NumBitsLeft() { + return (num_remaining_bits_in_curr_byte_ + bytes_left_ * 8); + } + + bool H264BitReader::HasMoreRBSPData() { + // Make sure we have more bits, if we are at 0 bits in current byte and + // updating current byte fails, we don't have more data anyway. + if (num_remaining_bits_in_curr_byte_ == 0 && !UpdateCurrByte()) + return false; + + // If there is no more RBSP data, then |curr_byte_| contains the stop bit and + // zero padding. Check to see if there is other data instead. + // (We don't actually check for the stop bit itself, instead treating the + // invalid case of all trailing zeros identically). + if ((curr_byte_ & ((1 << (num_remaining_bits_in_curr_byte_ - 1)) - 1)) != 0) + return true; + + // While the spec disallows it (7.4.1: "The last byte of the NAL unit shall + // not be equal to 0x00"), some streams have trailing null bytes anyway. We + // don't handle emulation prevention sequences because HasMoreRBSPData() is + // not used when parsing slices (where cabac_zero_word elements are legal). + for (off_t i = 0; i < bytes_left_; i++) { + if (data_[i] != 0) + return true; + } + + bytes_left_ = 0; + return false; + } + + size_t H264BitReader::NumEmulationPreventionBytesRead() { + return emulation_prevention_bytes_; + } + +} // namespace media diff --git a/src/H264/h264_bit_reader.h b/src/H264/h264_bit_reader.h new file mode 100644 index 00000000..75569e48 --- /dev/null +++ b/src/H264/h264_bit_reader.h @@ -0,0 +1,81 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains an implementation of an H264 Annex-B video stream parser. + +#ifndef MEDIA_FILTERS_H264_BIT_READER_H_ +#define MEDIA_FILTERS_H264_BIT_READER_H_ + +#include +#include +#include +#include "macros.h" + +using namespace std; + +namespace media { + + // A class to provide bit-granularity reading of H.264 streams. + // This is not a generic bit reader class, as it takes into account + // H.264 stream-specific constraints, such as skipping emulation-prevention + // bytes and stop bits. See spec for more details. + class MEDIA_EXPORT H264BitReader { + public: + H264BitReader(); + ~H264BitReader(); + + // Initialize the reader to start reading at |data|, |size| being size + // of |data| in bytes. + // Return false on insufficient size of stream.. + // TODO(posciak,fischman): consider replacing Initialize() with + // heap-allocating and creating bit readers on demand instead. + bool Initialize(const uint8_t* data, off_t size); + + // Read |num_bits| next bits from stream and return in |*out|, first bit + // from the stream starting at |num_bits| position in |*out|. + // |num_bits| may be 1-32, inclusive. + // Return false if the given number of bits cannot be read (not enough + // bits in the stream), true otherwise. + bool ReadBits(int num_bits, int* out); + + // Return the number of bits left in the stream. + off_t NumBitsLeft(); + + // See the definition of more_rbsp_data() in spec. + bool HasMoreRBSPData(); + + // Return the number of emulation prevention bytes already read. + size_t NumEmulationPreventionBytesRead(); + + private: + // Advance to the next byte, loading it into curr_byte_. + // Return false on end of stream. + bool UpdateCurrByte(); + + // Pointer to the next unread (not in curr_byte_) byte in the stream. + const uint8_t* data_; + + // Bytes left in the stream (without the curr_byte_). + off_t bytes_left_; + + // Contents of the current byte; first unread bit starting at position + // 8 - num_remaining_bits_in_curr_byte_ from MSB. + int curr_byte_; + + // Number of bits remaining in curr_byte_ + int num_remaining_bits_in_curr_byte_; + + // Used in emulation prevention three byte detection (see spec). + // Initially set to 0xffff to accept all initial two-byte sequences. + int prev_two_bytes_; + + // Number of emulation preventation bytes (0x000003) we met. + size_t emulation_prevention_bytes_; + + DISALLOW_COPY_AND_ASSIGN(H264BitReader); + }; + +} // namespace media + +#endif // MEDIA_FILTERS_H264_BIT_READER_H_ diff --git a/src/H264/h264_parser.cpp b/src/H264/h264_parser.cpp new file mode 100644 index 00000000..20b0ad39 --- /dev/null +++ b/src/H264/h264_parser.cpp @@ -0,0 +1,1372 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "h264_parser.h" +#include +#include +#include "macros.h" +#include "Util/logger.h" +using namespace ZL::Util; + + +template +void STLDeleteContainerPairSecondPointers(ForwardIterator begin, + ForwardIterator end) { + while (begin != end) { + ForwardIterator temp = begin; + ++begin; + delete temp->second; + } +} + +template +void STLDeleteValues(T* container) { + if (!container) + return; + STLDeleteContainerPairSecondPointers(container->begin(), container->end()); + container->clear(); +} + +namespace media { + + bool H264SliceHeader::IsPSlice() const { + return (slice_type % 5 == kPSlice); + } + + bool H264SliceHeader::IsBSlice() const { + return (slice_type % 5 == kBSlice); + } + + bool H264SliceHeader::IsISlice() const { + return (slice_type % 5 == kISlice); + } + + bool H264SliceHeader::IsSPSlice() const { + return (slice_type % 5 == kSPSlice); + } + + bool H264SliceHeader::IsSISlice() const { + return (slice_type % 5 == kSISlice); + } + + H264NALU::H264NALU() { + memset(this, 0, sizeof(*this)); + } + + H264SPS::H264SPS() { + memset(this, 0, sizeof(*this)); + } + + H264PPS::H264PPS() { + memset(this, 0, sizeof(*this)); + } + + H264SliceHeader::H264SliceHeader() { + memset(this, 0, sizeof(*this)); + } + + H264SEIMessage::H264SEIMessage() { + memset(this, 0, sizeof(*this)); + } + +#define READ_BITS_OR_RETURN(num_bits, out) \ +do { \ +int _out; \ +if (!br_.ReadBits(num_bits, &_out)) { \ +DebugL \ +<< "Error in stream: unexpected EOS while trying to read " #out; \ +return kInvalidStream; \ +} \ +*out = _out; \ +} while (0) + +#define READ_BOOL_OR_RETURN(out) \ +do { \ +int _out; \ +if (!br_.ReadBits(1, &_out)) { \ +DebugL \ +<< "Error in stream: unexpected EOS while trying to read " #out; \ +return kInvalidStream; \ +} \ +*out = _out != 0; \ +} while (0) + +#define READ_UE_OR_RETURN(out) \ +do { \ +if (ReadUE(out) != kOk) { \ +DebugL << "Error in stream: invalid value while trying to read " #out; \ +return kInvalidStream; \ +} \ +} while (0) + +#define READ_SE_OR_RETURN(out) \ +do { \ +if (ReadSE(out) != kOk) { \ +DebugL << "Error in stream: invalid value while trying to read " #out; \ +return kInvalidStream; \ +} \ +} while (0) + +#define IN_RANGE_OR_RETURN(val, min, max) \ +do { \ +if ((val) < (min) || (val) > (max)) { \ +DebugL << "Error in stream: invalid value, expected " #val " to be" \ +<< " in range [" << (min) << ":" << (max) << "]" \ +<< " found " << (val) << " instead"; \ +return kInvalidStream; \ +} \ +} while (0) + +#define TRUE_OR_RETURN(a) \ +do { \ +if (!(a)) { \ +DebugL << "Error in stream: invalid value, expected " << #a; \ +return kInvalidStream; \ +} \ +} while (0) + + // ISO 14496 part 10 + // VUI parameters: Table E-1 "Meaning of sample aspect ratio indicator" + static const int kTableSarWidth[] = { + 0, 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2 + }; + static const int kTableSarHeight[] = { + 0, 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1 + }; + static_assert(arraysize(kTableSarWidth) == arraysize(kTableSarHeight), + "sar tables must have the same size"); + + H264Parser::H264Parser() { + Reset(); + } + + H264Parser::~H264Parser() { + STLDeleteValues(&active_SPSes_); + STLDeleteValues(&active_PPSes_); + } + + void H264Parser::Reset() { + stream_ = NULL; + bytes_left_ = 0; + encrypted_ranges_.clear(); + } + + void H264Parser::SetStream(const uint8_t* stream, off_t stream_size) { + std::vector subsamples; + SetEncryptedStream(stream, stream_size, subsamples); + } + + void H264Parser::SetEncryptedStream(const uint8_t* stream, + off_t stream_size, + const std::vector& subsamples) { + DCHECK(stream); + DCHECK_GT(stream_size, 0); + + stream_ = stream; + bytes_left_ = stream_size; + + encrypted_ranges_.clear(); + const uint8_t* start = stream; + const uint8_t* stream_end = stream_ + bytes_left_; + for (size_t i = 0; i < subsamples.size() && start < stream_end; ++i) { + start += subsamples[i].clear_bytes; + + const uint8_t* end = + std::min(start + subsamples[i].cypher_bytes, stream_end); + encrypted_ranges_.Add(start, end); + start = end; + } + } + + const H264PPS* H264Parser::GetPPS(int pps_id) const { + auto it = active_PPSes_.find(pps_id); + if (it == active_PPSes_.end()) { + DebugL << "Requested a nonexistent PPS id " << pps_id; + return nullptr; + } + + return it->second; + } + + const H264SPS* H264Parser::GetSPS(int sps_id) const { + auto it = active_SPSes_.find(sps_id); + if (it == active_SPSes_.end()) { + DebugL << "Requested a nonexistent SPS id " << sps_id; + return nullptr; + } + + return it->second; + } + + static inline bool IsStartCode(const uint8_t* data) { + return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01; + } + + // static + bool H264Parser::FindStartCode(const uint8_t* data, + off_t data_size, + off_t* offset, + off_t* start_code_size) { + DCHECK_GE(data_size, 0); + off_t bytes_left = data_size; + + while (bytes_left >= 3) { + if (IsStartCode(data)) { + // Found three-byte start code, set pointer at its beginning. + *offset = data_size - bytes_left; + *start_code_size = 3; + + // If there is a zero byte before this start code, + // then it's actually a four-byte start code, so backtrack one byte. + if (*offset > 0 && *(data - 1) == 0x00) { + --(*offset); + ++(*start_code_size); + } + + return true; + } + + ++data; + --bytes_left; + } + + // End of data: offset is pointing to the first byte that was not considered + // as a possible start of a start code. + // Note: there is no security issue when receiving a negative |data_size| + // since in this case, |bytes_left| is equal to |data_size| and thus + // |*offset| is equal to 0 (valid offset). + *offset = data_size - bytes_left; + *start_code_size = 0; + return false; + } + + bool H264Parser::LocateNALU(off_t* nalu_size, off_t* start_code_size) { + // Find the start code of next NALU. + off_t nalu_start_off = 0; + off_t annexb_start_code_size = 0; + + if (!FindStartCodeInClearRanges(stream_, bytes_left_, + encrypted_ranges_, + &nalu_start_off, &annexb_start_code_size)) { + //DebugL << "Could not find start code, end of stream?"; + return false; + } + + // Move the stream to the beginning of the NALU (pointing at the start code). + stream_ += nalu_start_off; + bytes_left_ -= nalu_start_off; + + const uint8_t* nalu_data = stream_ + annexb_start_code_size; + off_t max_nalu_data_size = bytes_left_ - annexb_start_code_size; + if (max_nalu_data_size <= 0) { + DebugL << "End of stream"; + return false; + } + + // Find the start code of next NALU; + // if successful, |nalu_size_without_start_code| is the number of bytes from + // after previous start code to before this one; + // if next start code is not found, it is still a valid NALU since there + // are some bytes left after the first start code: all the remaining bytes + // belong to the current NALU. + off_t next_start_code_size = 0; + off_t nalu_size_without_start_code = 0; + if (!FindStartCodeInClearRanges(nalu_data, max_nalu_data_size, + encrypted_ranges_, + &nalu_size_without_start_code, + &next_start_code_size)) { + nalu_size_without_start_code = max_nalu_data_size; + } + *nalu_size = nalu_size_without_start_code + annexb_start_code_size; + *start_code_size = annexb_start_code_size; + return true; + } + + bool H264Parser::FindStartCodeInClearRanges( + const uint8_t* data, + off_t data_size, + const Ranges& encrypted_ranges, + off_t* offset, + off_t* start_code_size) { + if (encrypted_ranges.size() == 0) + return FindStartCode(data, data_size, offset, start_code_size); + + DCHECK_GE(data_size, 0); + const uint8_t* start = data; + do { + off_t bytes_left = data_size - (start - data); + + if (!FindStartCode(start, bytes_left, offset, start_code_size)) + return false; + + // Construct a Ranges object that represents the region occupied + // by the start code and the 1 byte needed to read the NAL unit type. + const uint8_t* start_code = start + *offset; + const uint8_t* start_code_end = start_code + *start_code_size; + Ranges start_code_range; + start_code_range.Add(start_code, start_code_end + 1); + + if (encrypted_ranges.IntersectionWith(start_code_range).size() > 0) { + // The start code is inside an encrypted section so we need to scan + // for another start code. + *start_code_size = 0; + start += std::min(*offset + 1, bytes_left); + } + } while (*start_code_size == 0); + + // Update |*offset| to include the data we skipped over. + *offset += start - data; + return true; + } + + H264Parser::Result H264Parser::ReadUE(int* val) { + int num_bits = -1; + int bit; + int rest; + + // Count the number of contiguous zero bits. + do { + READ_BITS_OR_RETURN(1, &bit); + num_bits++; + } while (bit == 0); + + if (num_bits > 31) + return kInvalidStream; + + // Calculate exp-Golomb code value of size num_bits. + // Special case for |num_bits| == 31 to avoid integer overflow. The only + // valid representation as an int is 2^31 - 1, so the remaining bits must + // be 0 or else the number is too large. + *val = (1u << num_bits) - 1u; + + if (num_bits == 31) { + READ_BITS_OR_RETURN(num_bits, &rest); + return (rest == 0) ? kOk : kInvalidStream; + } + + if (num_bits > 0) { + READ_BITS_OR_RETURN(num_bits, &rest); + *val += rest; + } + + return kOk; + } + + H264Parser::Result H264Parser::ReadSE(int* val) { + int ue; + Result res; + + // See Chapter 9 in the spec. + res = ReadUE(&ue); + if (res != kOk) + return res; + + if (ue % 2 == 0) + *val = -(ue / 2); + else + *val = ue / 2 + 1; + + return kOk; + } + + H264Parser::Result H264Parser::AdvanceToNextNALU(H264NALU* nalu) { + off_t start_code_size; + off_t nalu_size_with_start_code; + if (!LocateNALU(&nalu_size_with_start_code, &start_code_size)) { + //DebugL << "Could not find next NALU, bytes left in stream: " << bytes_left_; + return kEOStream; + } + + nalu->data = stream_ + start_code_size; + nalu->size = nalu_size_with_start_code - start_code_size; + //DebugL << "NALU found: size=" << nalu_size_with_start_code; + + // Initialize bit reader at the start of found NALU. + if (!br_.Initialize(nalu->data, nalu->size)) + return kEOStream; + + // Move parser state to after this NALU, so next time AdvanceToNextNALU + // is called, we will effectively be skipping it; + // other parsing functions will use the position saved + // in bit reader for parsing, so we don't have to remember it here. + stream_ += nalu_size_with_start_code; + bytes_left_ -= nalu_size_with_start_code; + + // Read NALU header, skip the forbidden_zero_bit, but check for it. + int data; + READ_BITS_OR_RETURN(1, &data); + TRUE_OR_RETURN(data == 0); + + READ_BITS_OR_RETURN(2, &nalu->nal_ref_idc); + READ_BITS_OR_RETURN(5, &nalu->nal_unit_type); + + /*DebugL << "NALU type: " << static_cast(nalu->nal_unit_type) + << " at: " << reinterpret_cast(nalu->data) + << " size: " << nalu->size + << " ref: " << static_cast(nalu->nal_ref_idc); + */ + + return kOk; + } + + // Default scaling lists (per spec). + static const int kDefault4x4Intra[kH264ScalingList4x4Length] = { + 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42, }; + + static const int kDefault4x4Inter[kH264ScalingList4x4Length] = { + 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34, }; + + static const int kDefault8x8Intra[kH264ScalingList8x8Length] = { + 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, + 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, + 31, 33, 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42, }; + + static const int kDefault8x8Inter[kH264ScalingList8x8Length] = { + 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, + 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, + 27, 28, 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35, }; + + static inline void DefaultScalingList4x4( + int i, + int scaling_list4x4[][kH264ScalingList4x4Length]) { + DCHECK_LT(i, 6); + + if (i < 3) + memcpy(scaling_list4x4[i], kDefault4x4Intra, sizeof(kDefault4x4Intra)); + else if (i < 6) + memcpy(scaling_list4x4[i], kDefault4x4Inter, sizeof(kDefault4x4Inter)); + } + + static inline void DefaultScalingList8x8( + int i, + int scaling_list8x8[][kH264ScalingList8x8Length]) { + DCHECK_LT(i, 6); + + if (i % 2 == 0) + memcpy(scaling_list8x8[i], kDefault8x8Intra, sizeof(kDefault8x8Intra)); + else + memcpy(scaling_list8x8[i], kDefault8x8Inter, sizeof(kDefault8x8Inter)); + } + + static void FallbackScalingList4x4( + int i, + const int default_scaling_list_intra[], + const int default_scaling_list_inter[], + int scaling_list4x4[][kH264ScalingList4x4Length]) { + static const int kScalingList4x4ByteSize = + sizeof(scaling_list4x4[0][0]) * kH264ScalingList4x4Length; + + switch (i) { + case 0: + memcpy(scaling_list4x4[i], default_scaling_list_intra, + kScalingList4x4ByteSize); + break; + + case 1: + memcpy(scaling_list4x4[i], scaling_list4x4[0], kScalingList4x4ByteSize); + break; + + case 2: + memcpy(scaling_list4x4[i], scaling_list4x4[1], kScalingList4x4ByteSize); + break; + + case 3: + memcpy(scaling_list4x4[i], default_scaling_list_inter, + kScalingList4x4ByteSize); + break; + + case 4: + memcpy(scaling_list4x4[i], scaling_list4x4[3], kScalingList4x4ByteSize); + break; + + case 5: + memcpy(scaling_list4x4[i], scaling_list4x4[4], kScalingList4x4ByteSize); + break; + + default: + NOTREACHED(); + break; + } + } + + static void FallbackScalingList8x8( + int i, + const int default_scaling_list_intra[], + const int default_scaling_list_inter[], + int scaling_list8x8[][kH264ScalingList8x8Length]) { + static const int kScalingList8x8ByteSize = + sizeof(scaling_list8x8[0][0]) * kH264ScalingList8x8Length; + + switch (i) { + case 0: + memcpy(scaling_list8x8[i], default_scaling_list_intra, + kScalingList8x8ByteSize); + break; + + case 1: + memcpy(scaling_list8x8[i], default_scaling_list_inter, + kScalingList8x8ByteSize); + break; + + case 2: + memcpy(scaling_list8x8[i], scaling_list8x8[0], kScalingList8x8ByteSize); + break; + + case 3: + memcpy(scaling_list8x8[i], scaling_list8x8[1], kScalingList8x8ByteSize); + break; + + case 4: + memcpy(scaling_list8x8[i], scaling_list8x8[2], kScalingList8x8ByteSize); + break; + + case 5: + memcpy(scaling_list8x8[i], scaling_list8x8[3], kScalingList8x8ByteSize); + break; + + default: + NOTREACHED(); + break; + } + } + + H264Parser::Result H264Parser::ParseScalingList(int size, + int* scaling_list, + bool* use_default) { + // See chapter 7.3.2.1.1.1. + int last_scale = 8; + int next_scale = 8; + int delta_scale; + + *use_default = false; + + for (int j = 0; j < size; ++j) { + if (next_scale != 0) { + READ_SE_OR_RETURN(&delta_scale); + IN_RANGE_OR_RETURN(delta_scale, -128, 127); + next_scale = (last_scale + delta_scale + 256) & 0xff; + + if (j == 0 && next_scale == 0) { + *use_default = true; + return kOk; + } + } + + scaling_list[j] = (next_scale == 0) ? last_scale : next_scale; + last_scale = scaling_list[j]; + } + + return kOk; + } + + H264Parser::Result H264Parser::ParseSPSScalingLists(H264SPS* sps) { + // See 7.4.2.1.1. + bool seq_scaling_list_present_flag; + bool use_default; + Result res; + + // Parse scaling_list4x4. + for (int i = 0; i < 6; ++i) { + READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag); + + if (seq_scaling_list_present_flag) { + res = ParseScalingList(arraysize(sps->scaling_list4x4[i]), + sps->scaling_list4x4[i], + &use_default); + if (res != kOk) + return res; + + if (use_default) + DefaultScalingList4x4(i, sps->scaling_list4x4); + + } else { + FallbackScalingList4x4( + i, kDefault4x4Intra, kDefault4x4Inter, sps->scaling_list4x4); + } + } + + // Parse scaling_list8x8. + for (int i = 0; i < ((sps->chroma_format_idc != 3) ? 2 : 6); ++i) { + READ_BOOL_OR_RETURN(&seq_scaling_list_present_flag); + + if (seq_scaling_list_present_flag) { + res = ParseScalingList(arraysize(sps->scaling_list8x8[i]), + sps->scaling_list8x8[i], + &use_default); + if (res != kOk) + return res; + + if (use_default) + DefaultScalingList8x8(i, sps->scaling_list8x8); + + } else { + FallbackScalingList8x8( + i, kDefault8x8Intra, kDefault8x8Inter, sps->scaling_list8x8); + } + } + + return kOk; + } + + H264Parser::Result H264Parser::ParsePPSScalingLists(const H264SPS& sps, + H264PPS* pps) { + // See 7.4.2.2. + bool pic_scaling_list_present_flag; + bool use_default; + Result res; + + for (int i = 0; i < 6; ++i) { + READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag); + + if (pic_scaling_list_present_flag) { + res = ParseScalingList(arraysize(pps->scaling_list4x4[i]), + pps->scaling_list4x4[i], + &use_default); + if (res != kOk) + return res; + + if (use_default) + DefaultScalingList4x4(i, pps->scaling_list4x4); + + } else { + if (sps.seq_scaling_matrix_present_flag) { + // Table 7-2 fallback rule A in spec. + FallbackScalingList4x4( + i, kDefault4x4Intra, kDefault4x4Inter, pps->scaling_list4x4); + } else { + // Table 7-2 fallback rule B in spec. + FallbackScalingList4x4(i, + sps.scaling_list4x4[0], + sps.scaling_list4x4[3], + pps->scaling_list4x4); + } + } + } + + if (pps->transform_8x8_mode_flag) { + for (int i = 0; i < ((sps.chroma_format_idc != 3) ? 2 : 6); ++i) { + READ_BOOL_OR_RETURN(&pic_scaling_list_present_flag); + + if (pic_scaling_list_present_flag) { + res = ParseScalingList(arraysize(pps->scaling_list8x8[i]), + pps->scaling_list8x8[i], + &use_default); + if (res != kOk) + return res; + + if (use_default) + DefaultScalingList8x8(i, pps->scaling_list8x8); + + } else { + if (sps.seq_scaling_matrix_present_flag) { + // Table 7-2 fallback rule A in spec. + FallbackScalingList8x8( + i, kDefault8x8Intra, kDefault8x8Inter, pps->scaling_list8x8); + } else { + // Table 7-2 fallback rule B in spec. + FallbackScalingList8x8(i, + sps.scaling_list8x8[0], + sps.scaling_list8x8[1], + pps->scaling_list8x8); + } + } + } + } + return kOk; + } + + H264Parser::Result H264Parser::ParseAndIgnoreHRDParameters( + bool* hrd_parameters_present) { + int data; + READ_BOOL_OR_RETURN(&data); // {nal,vcl}_hrd_parameters_present_flag + if (!data) + return kOk; + + *hrd_parameters_present = true; + + int cpb_cnt_minus1; + READ_UE_OR_RETURN(&cpb_cnt_minus1); + IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31); + READ_BITS_OR_RETURN(8, &data); // bit_rate_scale, cpb_size_scale + for (int i = 0; i <= cpb_cnt_minus1; ++i) { + READ_UE_OR_RETURN(&data); // bit_rate_value_minus1[i] + READ_UE_OR_RETURN(&data); // cpb_size_value_minus1[i] + READ_BOOL_OR_RETURN(&data); // cbr_flag + } + READ_BITS_OR_RETURN(20, &data); // cpb/dpb delays, etc. + + return kOk; + } + + H264Parser::Result H264Parser::ParseVUIParameters(H264SPS* sps) { + bool aspect_ratio_info_present_flag; + READ_BOOL_OR_RETURN(&aspect_ratio_info_present_flag); + if (aspect_ratio_info_present_flag) { + int aspect_ratio_idc; + READ_BITS_OR_RETURN(8, &aspect_ratio_idc); + if (aspect_ratio_idc == H264SPS::kExtendedSar) { + READ_BITS_OR_RETURN(16, &sps->sar_width); + READ_BITS_OR_RETURN(16, &sps->sar_height); + } else { + const int max_aspect_ratio_idc = arraysize(kTableSarWidth) - 1; + IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc); + sps->sar_width = kTableSarWidth[aspect_ratio_idc]; + sps->sar_height = kTableSarHeight[aspect_ratio_idc]; + } + } + + int data; + // Read and ignore overscan and video signal type info. + READ_BOOL_OR_RETURN(&data); // overscan_info_present_flag + if (data) + READ_BOOL_OR_RETURN(&data); // overscan_appropriate_flag + + READ_BOOL_OR_RETURN(&data); // video_signal_type_present_flag + if (data) { + READ_BITS_OR_RETURN(3, &data); // video_format + READ_BOOL_OR_RETURN(&data); // video_full_range_flag + READ_BOOL_OR_RETURN(&data); // colour_description_present_flag + if (data) + READ_BITS_OR_RETURN(24, &data); // color description syntax elements + } + + READ_BOOL_OR_RETURN(&data); // chroma_loc_info_present_flag + if (data) { + READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_top_field + READ_UE_OR_RETURN(&data); // chroma_sample_loc_type_bottom_field + } + + // Read and ignore timing info. + READ_BOOL_OR_RETURN(&data); // timing_info_present_flag + if (data) { + READ_BITS_OR_RETURN(16, &data); // num_units_in_tick + READ_BITS_OR_RETURN(16, &data); // num_units_in_tick + READ_BITS_OR_RETURN(16, &data); // time_scale + READ_BITS_OR_RETURN(16, &data); // time_scale + READ_BOOL_OR_RETURN(&data); // fixed_frame_rate_flag + } + + // Read and ignore NAL HRD parameters, if present. + bool hrd_parameters_present = false; + Result res = ParseAndIgnoreHRDParameters(&hrd_parameters_present); + if (res != kOk) + return res; + + // Read and ignore VCL HRD parameters, if present. + res = ParseAndIgnoreHRDParameters(&hrd_parameters_present); + if (res != kOk) + return res; + + if (hrd_parameters_present) // One of NAL or VCL params present is enough. + READ_BOOL_OR_RETURN(&data); // low_delay_hrd_flag + + READ_BOOL_OR_RETURN(&data); // pic_struct_present_flag + READ_BOOL_OR_RETURN(&sps->bitstream_restriction_flag); + if (sps->bitstream_restriction_flag) { + READ_BOOL_OR_RETURN(&data); // motion_vectors_over_pic_boundaries_flag + READ_UE_OR_RETURN(&data); // max_bytes_per_pic_denom + READ_UE_OR_RETURN(&data); // max_bits_per_mb_denom + READ_UE_OR_RETURN(&data); // log2_max_mv_length_horizontal + READ_UE_OR_RETURN(&data); // log2_max_mv_length_vertical + READ_UE_OR_RETURN(&sps->max_num_reorder_frames); + READ_UE_OR_RETURN(&sps->max_dec_frame_buffering); + TRUE_OR_RETURN(sps->max_dec_frame_buffering >= sps->max_num_ref_frames); + IN_RANGE_OR_RETURN( + sps->max_num_reorder_frames, 0, sps->max_dec_frame_buffering); + } + + return kOk; + } + + static void FillDefaultSeqScalingLists(H264SPS* sps) { + for (int i = 0; i < 6; ++i) + for (int j = 0; j < kH264ScalingList4x4Length; ++j) + sps->scaling_list4x4[i][j] = 16; + + for (int i = 0; i < 6; ++i) + for (int j = 0; j < kH264ScalingList8x8Length; ++j) + sps->scaling_list8x8[i][j] = 16; + } + + H264Parser::Result H264Parser::ParseSPS(int* sps_id) { + // See 7.4.2.1. + int data; + Result res; + + *sps_id = -1; + + std::unique_ptr sps(new H264SPS()); + + READ_BITS_OR_RETURN(8, &sps->profile_idc); + READ_BOOL_OR_RETURN(&sps->constraint_set0_flag); + READ_BOOL_OR_RETURN(&sps->constraint_set1_flag); + READ_BOOL_OR_RETURN(&sps->constraint_set2_flag); + READ_BOOL_OR_RETURN(&sps->constraint_set3_flag); + READ_BOOL_OR_RETURN(&sps->constraint_set4_flag); + READ_BOOL_OR_RETURN(&sps->constraint_set5_flag); + READ_BITS_OR_RETURN(2, &data); // reserved_zero_2bits + READ_BITS_OR_RETURN(8, &sps->level_idc); + READ_UE_OR_RETURN(&sps->seq_parameter_set_id); + TRUE_OR_RETURN(sps->seq_parameter_set_id < 32); + + if (sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244 || + sps->profile_idc == 44 || sps->profile_idc == 83 || + sps->profile_idc == 86 || sps->profile_idc == 118 || + sps->profile_idc == 128) { + READ_UE_OR_RETURN(&sps->chroma_format_idc); + TRUE_OR_RETURN(sps->chroma_format_idc < 4); + + if (sps->chroma_format_idc == 3) + READ_BOOL_OR_RETURN(&sps->separate_colour_plane_flag); + + READ_UE_OR_RETURN(&sps->bit_depth_luma_minus8); + TRUE_OR_RETURN(sps->bit_depth_luma_minus8 < 7); + + READ_UE_OR_RETURN(&sps->bit_depth_chroma_minus8); + TRUE_OR_RETURN(sps->bit_depth_chroma_minus8 < 7); + + READ_BOOL_OR_RETURN(&sps->qpprime_y_zero_transform_bypass_flag); + READ_BOOL_OR_RETURN(&sps->seq_scaling_matrix_present_flag); + + if (sps->seq_scaling_matrix_present_flag) { + //DebugL << "Scaling matrix present"; + res = ParseSPSScalingLists(sps.get()); + if (res != kOk) + return res; + } else { + FillDefaultSeqScalingLists(sps.get()); + } + } else { + sps->chroma_format_idc = 1; + FillDefaultSeqScalingLists(sps.get()); + } + + if (sps->separate_colour_plane_flag) + sps->chroma_array_type = 0; + else + sps->chroma_array_type = sps->chroma_format_idc; + + READ_UE_OR_RETURN(&sps->log2_max_frame_num_minus4); + TRUE_OR_RETURN(sps->log2_max_frame_num_minus4 < 13); + + READ_UE_OR_RETURN(&sps->pic_order_cnt_type); + TRUE_OR_RETURN(sps->pic_order_cnt_type < 3); + + sps->expected_delta_per_pic_order_cnt_cycle = 0; + if (sps->pic_order_cnt_type == 0) { + READ_UE_OR_RETURN(&sps->log2_max_pic_order_cnt_lsb_minus4); + TRUE_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 < 13); + } else if (sps->pic_order_cnt_type == 1) { + READ_BOOL_OR_RETURN(&sps->delta_pic_order_always_zero_flag); + READ_SE_OR_RETURN(&sps->offset_for_non_ref_pic); + READ_SE_OR_RETURN(&sps->offset_for_top_to_bottom_field); + READ_UE_OR_RETURN(&sps->num_ref_frames_in_pic_order_cnt_cycle); + TRUE_OR_RETURN(sps->num_ref_frames_in_pic_order_cnt_cycle < 255); + + for (int i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) { + READ_SE_OR_RETURN(&sps->offset_for_ref_frame[i]); + sps->expected_delta_per_pic_order_cnt_cycle += + sps->offset_for_ref_frame[i]; + } + } + + READ_UE_OR_RETURN(&sps->max_num_ref_frames); + READ_BOOL_OR_RETURN(&sps->gaps_in_frame_num_value_allowed_flag); + + READ_UE_OR_RETURN(&sps->pic_width_in_mbs_minus1); + READ_UE_OR_RETURN(&sps->pic_height_in_map_units_minus1); + + READ_BOOL_OR_RETURN(&sps->frame_mbs_only_flag); + if (!sps->frame_mbs_only_flag) + READ_BOOL_OR_RETURN(&sps->mb_adaptive_frame_field_flag); + + READ_BOOL_OR_RETURN(&sps->direct_8x8_inference_flag); + + READ_BOOL_OR_RETURN(&sps->frame_cropping_flag); + if (sps->frame_cropping_flag) { + READ_UE_OR_RETURN(&sps->frame_crop_left_offset); + READ_UE_OR_RETURN(&sps->frame_crop_right_offset); + READ_UE_OR_RETURN(&sps->frame_crop_top_offset); + READ_UE_OR_RETURN(&sps->frame_crop_bottom_offset); + } + + READ_BOOL_OR_RETURN(&sps->vui_parameters_present_flag); + if (sps->vui_parameters_present_flag) { + //DebugL << "VUI parameters present"; + res = ParseVUIParameters(sps.get()); + if (res != kOk) + return res; + } + + // If an SPS with the same id already exists, replace it. + *sps_id = sps->seq_parameter_set_id; + delete active_SPSes_[*sps_id]; + active_SPSes_[*sps_id] = sps.release(); + + return kOk; + } + + H264Parser::Result H264Parser::ParsePPS(int* pps_id) { + // See 7.4.2.2. + const H264SPS* sps; + Result res; + + *pps_id = -1; + + std::unique_ptr pps(new H264PPS()); + + READ_UE_OR_RETURN(&pps->pic_parameter_set_id); + READ_UE_OR_RETURN(&pps->seq_parameter_set_id); + TRUE_OR_RETURN(pps->seq_parameter_set_id < 32); + + if (active_SPSes_.find(pps->seq_parameter_set_id) == active_SPSes_.end()) { + DebugL << "Invalid stream, no SPS id: " << pps->seq_parameter_set_id; + return kInvalidStream; + } + + sps = GetSPS(pps->seq_parameter_set_id); + TRUE_OR_RETURN(sps); + + READ_BOOL_OR_RETURN(&pps->entropy_coding_mode_flag); + READ_BOOL_OR_RETURN(&pps->bottom_field_pic_order_in_frame_present_flag); + + READ_UE_OR_RETURN(&pps->num_slice_groups_minus1); + if (pps->num_slice_groups_minus1 > 1) { + DebugL << "Slice groups not supported"; + return kUnsupportedStream; + } + + READ_UE_OR_RETURN(&pps->num_ref_idx_l0_default_active_minus1); + TRUE_OR_RETURN(pps->num_ref_idx_l0_default_active_minus1 < 32); + + READ_UE_OR_RETURN(&pps->num_ref_idx_l1_default_active_minus1); + TRUE_OR_RETURN(pps->num_ref_idx_l1_default_active_minus1 < 32); + + READ_BOOL_OR_RETURN(&pps->weighted_pred_flag); + READ_BITS_OR_RETURN(2, &pps->weighted_bipred_idc); + TRUE_OR_RETURN(pps->weighted_bipred_idc < 3); + + READ_SE_OR_RETURN(&pps->pic_init_qp_minus26); + IN_RANGE_OR_RETURN(pps->pic_init_qp_minus26, -26, 25); + + READ_SE_OR_RETURN(&pps->pic_init_qs_minus26); + IN_RANGE_OR_RETURN(pps->pic_init_qs_minus26, -26, 25); + + READ_SE_OR_RETURN(&pps->chroma_qp_index_offset); + IN_RANGE_OR_RETURN(pps->chroma_qp_index_offset, -12, 12); + pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset; + + READ_BOOL_OR_RETURN(&pps->deblocking_filter_control_present_flag); + READ_BOOL_OR_RETURN(&pps->constrained_intra_pred_flag); + READ_BOOL_OR_RETURN(&pps->redundant_pic_cnt_present_flag); + + if (br_.HasMoreRBSPData()) { + READ_BOOL_OR_RETURN(&pps->transform_8x8_mode_flag); + READ_BOOL_OR_RETURN(&pps->pic_scaling_matrix_present_flag); + + if (pps->pic_scaling_matrix_present_flag) { + DebugL << "Picture scaling matrix present"; + res = ParsePPSScalingLists(*sps, pps.get()); + if (res != kOk) + return res; + } + + READ_SE_OR_RETURN(&pps->second_chroma_qp_index_offset); + } + + // If a PPS with the same id already exists, replace it. + *pps_id = pps->pic_parameter_set_id; + delete active_PPSes_[*pps_id]; + active_PPSes_[*pps_id] = pps.release(); + + return kOk; + } + + H264Parser::Result H264Parser::ParseRefPicListModification( + int num_ref_idx_active_minus1, + H264ModificationOfPicNum* ref_list_mods) { + H264ModificationOfPicNum* pic_num_mod; + + if (num_ref_idx_active_minus1 >= 32) + return kInvalidStream; + + for (int i = 0; i < 32; ++i) { + pic_num_mod = &ref_list_mods[i]; + READ_UE_OR_RETURN(&pic_num_mod->modification_of_pic_nums_idc); + TRUE_OR_RETURN(pic_num_mod->modification_of_pic_nums_idc < 4); + + switch (pic_num_mod->modification_of_pic_nums_idc) { + case 0: + case 1: + READ_UE_OR_RETURN(&pic_num_mod->abs_diff_pic_num_minus1); + break; + + case 2: + READ_UE_OR_RETURN(&pic_num_mod->long_term_pic_num); + break; + + case 3: + // Per spec, list cannot be empty. + if (i == 0) + return kInvalidStream; + return kOk; + + default: + return kInvalidStream; + } + } + + // If we got here, we didn't get loop end marker prematurely, + // so make sure it is there for our client. + int modification_of_pic_nums_idc; + READ_UE_OR_RETURN(&modification_of_pic_nums_idc); + TRUE_OR_RETURN(modification_of_pic_nums_idc == 3); + + return kOk; + } + + H264Parser::Result H264Parser::ParseRefPicListModifications( + H264SliceHeader* shdr) { + Result res; + + if (!shdr->IsISlice() && !shdr->IsSISlice()) { + READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l0); + if (shdr->ref_pic_list_modification_flag_l0) { + res = ParseRefPicListModification(shdr->num_ref_idx_l0_active_minus1, + shdr->ref_list_l0_modifications); + if (res != kOk) + return res; + } + } + + if (shdr->IsBSlice()) { + READ_BOOL_OR_RETURN(&shdr->ref_pic_list_modification_flag_l1); + if (shdr->ref_pic_list_modification_flag_l1) { + res = ParseRefPicListModification(shdr->num_ref_idx_l1_active_minus1, + shdr->ref_list_l1_modifications); + if (res != kOk) + return res; + } + } + + return kOk; + } + + H264Parser::Result H264Parser::ParseWeightingFactors( + int num_ref_idx_active_minus1, + int chroma_array_type, + int luma_log2_weight_denom, + int chroma_log2_weight_denom, + H264WeightingFactors* w_facts) { + + int def_luma_weight = 1 << luma_log2_weight_denom; + int def_chroma_weight = 1 << chroma_log2_weight_denom; + + for (int i = 0; i < num_ref_idx_active_minus1 + 1; ++i) { + READ_BOOL_OR_RETURN(&w_facts->luma_weight_flag); + if (w_facts->luma_weight_flag) { + READ_SE_OR_RETURN(&w_facts->luma_weight[i]); + IN_RANGE_OR_RETURN(w_facts->luma_weight[i], -128, 127); + + READ_SE_OR_RETURN(&w_facts->luma_offset[i]); + IN_RANGE_OR_RETURN(w_facts->luma_offset[i], -128, 127); + } else { + w_facts->luma_weight[i] = def_luma_weight; + w_facts->luma_offset[i] = 0; + } + + if (chroma_array_type != 0) { + READ_BOOL_OR_RETURN(&w_facts->chroma_weight_flag); + if (w_facts->chroma_weight_flag) { + for (int j = 0; j < 2; ++j) { + READ_SE_OR_RETURN(&w_facts->chroma_weight[i][j]); + IN_RANGE_OR_RETURN(w_facts->chroma_weight[i][j], -128, 127); + + READ_SE_OR_RETURN(&w_facts->chroma_offset[i][j]); + IN_RANGE_OR_RETURN(w_facts->chroma_offset[i][j], -128, 127); + } + } else { + for (int j = 0; j < 2; ++j) { + w_facts->chroma_weight[i][j] = def_chroma_weight; + w_facts->chroma_offset[i][j] = 0; + } + } + } + } + + return kOk; + } + + H264Parser::Result H264Parser::ParsePredWeightTable(const H264SPS& sps, + H264SliceHeader* shdr) { + READ_UE_OR_RETURN(&shdr->luma_log2_weight_denom); + TRUE_OR_RETURN(shdr->luma_log2_weight_denom < 8); + + if (sps.chroma_array_type != 0) + READ_UE_OR_RETURN(&shdr->chroma_log2_weight_denom); + TRUE_OR_RETURN(shdr->chroma_log2_weight_denom < 8); + + Result res = ParseWeightingFactors(shdr->num_ref_idx_l0_active_minus1, + sps.chroma_array_type, + shdr->luma_log2_weight_denom, + shdr->chroma_log2_weight_denom, + &shdr->pred_weight_table_l0); + if (res != kOk) + return res; + + if (shdr->IsBSlice()) { + res = ParseWeightingFactors(shdr->num_ref_idx_l1_active_minus1, + sps.chroma_array_type, + shdr->luma_log2_weight_denom, + shdr->chroma_log2_weight_denom, + &shdr->pred_weight_table_l1); + if (res != kOk) + return res; + } + + return kOk; + } + + H264Parser::Result H264Parser::ParseDecRefPicMarking(H264SliceHeader* shdr) { + size_t bits_left_at_start = br_.NumBitsLeft(); + + if (shdr->idr_pic_flag) { + READ_BOOL_OR_RETURN(&shdr->no_output_of_prior_pics_flag); + READ_BOOL_OR_RETURN(&shdr->long_term_reference_flag); + } else { + READ_BOOL_OR_RETURN(&shdr->adaptive_ref_pic_marking_mode_flag); + + H264DecRefPicMarking* marking; + if (shdr->adaptive_ref_pic_marking_mode_flag) { + size_t i; + for (i = 0; i < arraysize(shdr->ref_pic_marking); ++i) { + marking = &shdr->ref_pic_marking[i]; + + READ_UE_OR_RETURN(&marking->memory_mgmnt_control_operation); + if (marking->memory_mgmnt_control_operation == 0) + break; + + if (marking->memory_mgmnt_control_operation == 1 || + marking->memory_mgmnt_control_operation == 3) + READ_UE_OR_RETURN(&marking->difference_of_pic_nums_minus1); + + if (marking->memory_mgmnt_control_operation == 2) + READ_UE_OR_RETURN(&marking->long_term_pic_num); + + if (marking->memory_mgmnt_control_operation == 3 || + marking->memory_mgmnt_control_operation == 6) + READ_UE_OR_RETURN(&marking->long_term_frame_idx); + + if (marking->memory_mgmnt_control_operation == 4) + READ_UE_OR_RETURN(&marking->max_long_term_frame_idx_plus1); + + if (marking->memory_mgmnt_control_operation > 6) + return kInvalidStream; + } + + if (i == arraysize(shdr->ref_pic_marking)) { + DebugL << "Ran out of dec ref pic marking fields"; + return kUnsupportedStream; + } + } + } + + shdr->dec_ref_pic_marking_bit_size = bits_left_at_start - br_.NumBitsLeft(); + return kOk; + } + + H264Parser::Result H264Parser::ParseSliceHeader(const H264NALU& nalu, + H264SliceHeader* shdr) { + // See 7.4.3. + const H264SPS* sps; + const H264PPS* pps; + Result res; + + memset(shdr, 0, sizeof(*shdr)); + + shdr->idr_pic_flag = (nalu.nal_unit_type == 5); + shdr->nal_ref_idc = nalu.nal_ref_idc; + shdr->nalu_data = nalu.data; + shdr->nalu_size = nalu.size; + + READ_UE_OR_RETURN(&shdr->first_mb_in_slice); + READ_UE_OR_RETURN(&shdr->slice_type); + TRUE_OR_RETURN(shdr->slice_type < 10); + + READ_UE_OR_RETURN(&shdr->pic_parameter_set_id); + + pps = GetPPS(shdr->pic_parameter_set_id); + TRUE_OR_RETURN(pps); + + sps = GetSPS(pps->seq_parameter_set_id); + TRUE_OR_RETURN(sps); + + if (sps->separate_colour_plane_flag) { + DebugL << "Interlaced streams not supported"; + return kUnsupportedStream; + } + + READ_BITS_OR_RETURN(sps->log2_max_frame_num_minus4 + 4, &shdr->frame_num); + if (!sps->frame_mbs_only_flag) { + READ_BOOL_OR_RETURN(&shdr->field_pic_flag); + if (shdr->field_pic_flag) { + DebugL << "Interlaced streams not supported"; + return kUnsupportedStream; + } + } + + if (shdr->idr_pic_flag) + READ_UE_OR_RETURN(&shdr->idr_pic_id); + + size_t bits_left_at_pic_order_cnt_start = br_.NumBitsLeft(); + if (sps->pic_order_cnt_type == 0) { + READ_BITS_OR_RETURN(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, + &shdr->pic_order_cnt_lsb); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !shdr->field_pic_flag) + READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt_bottom); + } + + if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) { + READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt0); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !shdr->field_pic_flag) + READ_SE_OR_RETURN(&shdr->delta_pic_order_cnt1); + } + + shdr->pic_order_cnt_bit_size = + bits_left_at_pic_order_cnt_start - br_.NumBitsLeft(); + + if (pps->redundant_pic_cnt_present_flag) { + READ_UE_OR_RETURN(&shdr->redundant_pic_cnt); + TRUE_OR_RETURN(shdr->redundant_pic_cnt < 128); + } + + if (shdr->IsBSlice()) + READ_BOOL_OR_RETURN(&shdr->direct_spatial_mv_pred_flag); + + if (shdr->IsPSlice() || shdr->IsSPSlice() || shdr->IsBSlice()) { + READ_BOOL_OR_RETURN(&shdr->num_ref_idx_active_override_flag); + if (shdr->num_ref_idx_active_override_flag) { + READ_UE_OR_RETURN(&shdr->num_ref_idx_l0_active_minus1); + if (shdr->IsBSlice()) + READ_UE_OR_RETURN(&shdr->num_ref_idx_l1_active_minus1); + } else { + shdr->num_ref_idx_l0_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1; + if (shdr->IsBSlice()) { + shdr->num_ref_idx_l1_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1; + } + } + } + if (shdr->field_pic_flag) { + TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 32); + TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 32); + } else { + TRUE_OR_RETURN(shdr->num_ref_idx_l0_active_minus1 < 16); + TRUE_OR_RETURN(shdr->num_ref_idx_l1_active_minus1 < 16); + } + + if (nalu.nal_unit_type == H264NALU::kCodedSliceExtension) { + return kUnsupportedStream; + } else { + res = ParseRefPicListModifications(shdr); + if (res != kOk) + return res; + } + + if ((pps->weighted_pred_flag && (shdr->IsPSlice() || shdr->IsSPSlice())) || + (pps->weighted_bipred_idc == 1 && shdr->IsBSlice())) { + res = ParsePredWeightTable(*sps, shdr); + if (res != kOk) + return res; + } + + if (nalu.nal_ref_idc != 0) { + res = ParseDecRefPicMarking(shdr); + if (res != kOk) + return res; + } + + if (pps->entropy_coding_mode_flag && !shdr->IsISlice() && + !shdr->IsSISlice()) { + READ_UE_OR_RETURN(&shdr->cabac_init_idc); + TRUE_OR_RETURN(shdr->cabac_init_idc < 3); + } + + READ_SE_OR_RETURN(&shdr->slice_qp_delta); + + if (shdr->IsSPSlice() || shdr->IsSISlice()) { + if (shdr->IsSPSlice()) + READ_BOOL_OR_RETURN(&shdr->sp_for_switch_flag); + READ_SE_OR_RETURN(&shdr->slice_qs_delta); + } + + if (pps->deblocking_filter_control_present_flag) { + READ_UE_OR_RETURN(&shdr->disable_deblocking_filter_idc); + TRUE_OR_RETURN(shdr->disable_deblocking_filter_idc < 3); + + if (shdr->disable_deblocking_filter_idc != 1) { + READ_SE_OR_RETURN(&shdr->slice_alpha_c0_offset_div2); + IN_RANGE_OR_RETURN(shdr->slice_alpha_c0_offset_div2, -6, 6); + + READ_SE_OR_RETURN(&shdr->slice_beta_offset_div2); + IN_RANGE_OR_RETURN(shdr->slice_beta_offset_div2, -6, 6); + } + } + + if (pps->num_slice_groups_minus1 > 0) { + DebugL << "Slice groups not supported"; + return kUnsupportedStream; + } + + size_t epb = br_.NumEmulationPreventionBytesRead(); + shdr->header_bit_size = (shdr->nalu_size - epb) * 8 - br_.NumBitsLeft(); + + return kOk; + } + + H264Parser::Result H264Parser::ParseSEI(H264SEIMessage* sei_msg) { + int byte; + + memset(sei_msg, 0, sizeof(*sei_msg)); + + READ_BITS_OR_RETURN(8, &byte); + while (byte == 0xff) { + sei_msg->type += 255; + READ_BITS_OR_RETURN(8, &byte); + } + sei_msg->type += byte; + + READ_BITS_OR_RETURN(8, &byte); + while (byte == 0xff) { + sei_msg->payload_size += 255; + READ_BITS_OR_RETURN(8, &byte); + } + sei_msg->payload_size += byte; + + DebugL << "Found SEI message type: " << sei_msg->type + << " payload size: " << sei_msg->payload_size; + + switch (sei_msg->type) { + case H264SEIMessage::kSEIRecoveryPoint: + READ_UE_OR_RETURN(&sei_msg->recovery_point.recovery_frame_cnt); + READ_BOOL_OR_RETURN(&sei_msg->recovery_point.exact_match_flag); + READ_BOOL_OR_RETURN(&sei_msg->recovery_point.broken_link_flag); + READ_BITS_OR_RETURN(2, &sei_msg->recovery_point.changing_slice_group_idc); + break; + + default: + DebugL << "Unsupported SEI message"; + break; + } + + return kOk; + } + +} // namespace media diff --git a/src/H264/h264_parser.h b/src/H264/h264_parser.h new file mode 100644 index 00000000..b2298257 --- /dev/null +++ b/src/H264/h264_parser.h @@ -0,0 +1,491 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file contains an implementation of an H264 Annex-B video stream parser. + +#ifndef MEDIA_FILTERS_H264_PARSER_H_ +#define MEDIA_FILTERS_H264_PARSER_H_ + +#include +#include +#include + +#include +#include + +#include "macros.h" +#include "h264_bit_reader.h" +#include "ranges.h" + +using namespace std; + +namespace media { + + struct SubsampleEntry { + uint32_t clear_bytes; + uint32_t cypher_bytes; + }; + + // For explanations of each struct and its members, see H.264 specification + // at http://www.itu.int/rec/T-REC-H.264. + struct MEDIA_EXPORT H264NALU { + H264NALU(); + + enum Type { + kUnspecified = 0, + kNonIDRSlice = 1, + kSliceDataA = 2, + kSliceDataB = 3, + kSliceDataC = 4, + kIDRSlice = 5, + kSEIMessage = 6, + kSPS = 7, + kPPS = 8, + kAUD = 9, + kEOSeq = 10, + kEOStream = 11, + kFiller = 12, + kSPSExt = 13, + kReserved14 = 14, + kReserved15 = 15, + kReserved16 = 16, + kReserved17 = 17, + kReserved18 = 18, + kCodedSliceAux = 19, + kCodedSliceExtension = 20, + }; + + // After (without) start code; we don't own the underlying memory + // and a shallow copy should be made when copying this struct. + const uint8_t* data; + off_t size; // From after start code to start code of next NALU (or EOS). + + int nal_ref_idc; + int nal_unit_type; + }; + + enum { + kH264ScalingList4x4Length = 16, + kH264ScalingList8x8Length = 64, + }; + + struct MEDIA_EXPORT H264SPS { + H264SPS(); + + enum H264ProfileIDC { + kProfileIDCBaseline = 66, + kProfileIDCConstrainedBaseline = kProfileIDCBaseline, + kProfileIDCMain = 77, + kProfileIDScalableBaseline = 83, + kProfileIDScalableHigh = 86, + kProfileIDCHigh = 100, + kProfileIDHigh10 = 110, + kProfileIDSMultiviewHigh = 118, + kProfileIDHigh422 = 122, + kProfileIDStereoHigh = 128, + kProfileIDHigh444Predictive = 244, + }; + + enum AspectRatioIdc { + kExtendedSar = 255, + }; + + enum { + // Constants for HRD parameters (spec ch. E.2.2). + kBitRateScaleConstantTerm = 6, // Equation E-37. + kCPBSizeScaleConstantTerm = 4, // Equation E-38. + kDefaultInitialCPBRemovalDelayLength = 24, + kDefaultDPBOutputDelayLength = 24, + kDefaultTimeOffsetLength = 24, + }; + + int profile_idc; + bool constraint_set0_flag; + bool constraint_set1_flag; + bool constraint_set2_flag; + bool constraint_set3_flag; + bool constraint_set4_flag; + bool constraint_set5_flag; + int level_idc; + int seq_parameter_set_id; + + int chroma_format_idc; + bool separate_colour_plane_flag; + int bit_depth_luma_minus8; + int bit_depth_chroma_minus8; + bool qpprime_y_zero_transform_bypass_flag; + + bool seq_scaling_matrix_present_flag; + int scaling_list4x4[6][kH264ScalingList4x4Length]; + int scaling_list8x8[6][kH264ScalingList8x8Length]; + + int log2_max_frame_num_minus4; + int pic_order_cnt_type; + int log2_max_pic_order_cnt_lsb_minus4; + bool delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + int num_ref_frames_in_pic_order_cnt_cycle; + int expected_delta_per_pic_order_cnt_cycle; // calculated + int offset_for_ref_frame[255]; + int max_num_ref_frames; + bool gaps_in_frame_num_value_allowed_flag; + int pic_width_in_mbs_minus1; + int pic_height_in_map_units_minus1; + bool frame_mbs_only_flag; + bool mb_adaptive_frame_field_flag; + bool direct_8x8_inference_flag; + bool frame_cropping_flag; + int frame_crop_left_offset; + int frame_crop_right_offset; + int frame_crop_top_offset; + int frame_crop_bottom_offset; + + bool vui_parameters_present_flag; + int sar_width; // Set to 0 when not specified. + int sar_height; // Set to 0 when not specified. + bool bitstream_restriction_flag; + int max_num_reorder_frames; + int max_dec_frame_buffering; + bool timing_info_present_flag; + int num_units_in_tick; + int time_scale; + bool fixed_frame_rate_flag; + + // TODO(posciak): actually parse these instead of ParseAndIgnoreHRDParameters. + bool nal_hrd_parameters_present_flag; + int cpb_cnt_minus1; + int bit_rate_scale; + int cpb_size_scale; + int bit_rate_value_minus1[32]; + int cpb_size_value_minus1[32]; + bool cbr_flag[32]; + int initial_cpb_removal_delay_length_minus_1; + int cpb_removal_delay_length_minus1; + int dpb_output_delay_length_minus1; + int time_offset_length; + + bool low_delay_hrd_flag; + + int chroma_array_type; + }; + + struct MEDIA_EXPORT H264PPS { + H264PPS(); + + int pic_parameter_set_id; + int seq_parameter_set_id; + bool entropy_coding_mode_flag; + bool bottom_field_pic_order_in_frame_present_flag; + int num_slice_groups_minus1; + // TODO(posciak): Slice groups not implemented, could be added at some point. + int num_ref_idx_l0_default_active_minus1; + int num_ref_idx_l1_default_active_minus1; + bool weighted_pred_flag; + int weighted_bipred_idc; + int pic_init_qp_minus26; + int pic_init_qs_minus26; + int chroma_qp_index_offset; + bool deblocking_filter_control_present_flag; + bool constrained_intra_pred_flag; + bool redundant_pic_cnt_present_flag; + bool transform_8x8_mode_flag; + + bool pic_scaling_matrix_present_flag; + int scaling_list4x4[6][kH264ScalingList4x4Length]; + int scaling_list8x8[6][kH264ScalingList8x8Length]; + + int second_chroma_qp_index_offset; + }; + + struct MEDIA_EXPORT H264ModificationOfPicNum { + int modification_of_pic_nums_idc; + union { + int abs_diff_pic_num_minus1; + int long_term_pic_num; + }; + }; + + struct MEDIA_EXPORT H264WeightingFactors { + bool luma_weight_flag; + bool chroma_weight_flag; + int luma_weight[32]; + int luma_offset[32]; + int chroma_weight[32][2]; + int chroma_offset[32][2]; + }; + + struct MEDIA_EXPORT H264DecRefPicMarking { + int memory_mgmnt_control_operation; + int difference_of_pic_nums_minus1; + int long_term_pic_num; + int long_term_frame_idx; + int max_long_term_frame_idx_plus1; + }; + + struct MEDIA_EXPORT H264SliceHeader { + H264SliceHeader(); + + enum { + kRefListSize = 32, + kRefListModSize = kRefListSize + }; + + enum Type { + kPSlice = 0, + kBSlice = 1, + kISlice = 2, + kSPSlice = 3, + kSISlice = 4, + }; + + bool IsPSlice() const; + bool IsBSlice() const; + bool IsISlice() const; + bool IsSPSlice() const; + bool IsSISlice() const; + + bool idr_pic_flag; // from NAL header + int nal_ref_idc; // from NAL header + const uint8_t* nalu_data; // from NAL header + off_t nalu_size; // from NAL header + off_t header_bit_size; // calculated + + int first_mb_in_slice; + int slice_type; + int pic_parameter_set_id; + int colour_plane_id; // TODO(posciak): use this! http://crbug.com/139878 + int frame_num; + bool field_pic_flag; + bool bottom_field_flag; + int idr_pic_id; + int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + int delta_pic_order_cnt0; + int delta_pic_order_cnt1; + int redundant_pic_cnt; + bool direct_spatial_mv_pred_flag; + + bool num_ref_idx_active_override_flag; + int num_ref_idx_l0_active_minus1; + int num_ref_idx_l1_active_minus1; + bool ref_pic_list_modification_flag_l0; + bool ref_pic_list_modification_flag_l1; + H264ModificationOfPicNum ref_list_l0_modifications[kRefListModSize]; + H264ModificationOfPicNum ref_list_l1_modifications[kRefListModSize]; + + int luma_log2_weight_denom; + int chroma_log2_weight_denom; + + bool luma_weight_l0_flag; + bool chroma_weight_l0_flag; + H264WeightingFactors pred_weight_table_l0; + + bool luma_weight_l1_flag; + bool chroma_weight_l1_flag; + H264WeightingFactors pred_weight_table_l1; + + bool no_output_of_prior_pics_flag; + bool long_term_reference_flag; + + bool adaptive_ref_pic_marking_mode_flag; + H264DecRefPicMarking ref_pic_marking[kRefListSize]; + + int cabac_init_idc; + int slice_qp_delta; + bool sp_for_switch_flag; + int slice_qs_delta; + int disable_deblocking_filter_idc; + int slice_alpha_c0_offset_div2; + int slice_beta_offset_div2; + + // Calculated. + // Size in bits of dec_ref_pic_marking() syntax element. + size_t dec_ref_pic_marking_bit_size; + size_t pic_order_cnt_bit_size; + }; + + struct H264SEIRecoveryPoint { + int recovery_frame_cnt; + bool exact_match_flag; + bool broken_link_flag; + int changing_slice_group_idc; + }; + + struct MEDIA_EXPORT H264SEIMessage { + H264SEIMessage(); + + enum Type { + kSEIRecoveryPoint = 6, + }; + + int type; + int payload_size; + union { + // Placeholder; in future more supported types will contribute to more + // union members here. + H264SEIRecoveryPoint recovery_point; + }; + }; + + // Class to parse an Annex-B H.264 stream, + // as specified in chapters 7 and Annex B of the H.264 spec. + class MEDIA_EXPORT H264Parser { + public: + enum Result { + kOk, + kInvalidStream, // error in stream + kUnsupportedStream, // stream not supported by the parser + kEOStream, // end of stream + }; + + // Find offset from start of data to next NALU start code + // and size of found start code (3 or 4 bytes). + // If no start code is found, offset is pointing to the first unprocessed byte + // (i.e. the first byte that was not considered as a possible start of a start + // code) and |*start_code_size| is set to 0. + // Preconditions: + // - |data_size| >= 0 + // Postconditions: + // - |*offset| is between 0 and |data_size| included. + // It is strictly less than |data_size| if |data_size| > 0. + // - |*start_code_size| is either 0, 3 or 4. + static bool FindStartCode(const uint8_t* data, + off_t data_size, + off_t* offset, + off_t* start_code_size); + + // Wrapper for FindStartCode() that skips over start codes that + // may appear inside of |encrypted_ranges_|. + // Returns true if a start code was found. Otherwise returns false. + static bool FindStartCodeInClearRanges(const uint8_t* data, + off_t data_size, + const Ranges& ranges, + off_t* offset, + off_t* start_code_size); + H264Parser(); + ~H264Parser(); + + void Reset(); + // Set current stream pointer to |stream| of |stream_size| in bytes, + // |stream| owned by caller. + // |subsamples| contains information about what parts of |stream| are + // encrypted. + void SetStream(const uint8_t* stream, off_t stream_size); + void SetEncryptedStream(const uint8_t* stream, + off_t stream_size, + const std::vector& subsamples); + + // Read the stream to find the next NALU, identify it and return + // that information in |*nalu|. This advances the stream to the beginning + // of this NALU, but not past it, so subsequent calls to NALU-specific + // parsing functions (ParseSPS, etc.) will parse this NALU. + // If the caller wishes to skip the current NALU, it can call this function + // again, instead of any NALU-type specific parse functions below. + Result AdvanceToNextNALU(H264NALU* nalu); + + // NALU-specific parsing functions. + // These should be called after AdvanceToNextNALU(). + + // SPSes and PPSes are owned by the parser class and the memory for their + // structures is managed here, not by the caller, as they are reused + // across NALUs. + // + // Parse an SPS/PPS NALU and save their data in the parser, returning id + // of the parsed structure in |*pps_id|/|*sps_id|. + // To get a pointer to a given SPS/PPS structure, use GetSPS()/GetPPS(), + // passing the returned |*sps_id|/|*pps_id| as parameter. + // TODO(posciak,fischman): consider replacing returning Result from Parse*() + // methods with a scoped_ptr and adding an AtEOS() function to check for EOS + // if Parse*() return NULL. + Result ParseSPS(int* sps_id); + Result ParsePPS(int* pps_id); + + // Return a pointer to SPS/PPS with given |sps_id|/|pps_id| or NULL if not + // present. + const H264SPS* GetSPS(int sps_id) const; + const H264PPS* GetPPS(int pps_id) const; + + // Slice headers and SEI messages are not used across NALUs by the parser + // and can be discarded after current NALU, so the parser does not store + // them, nor does it manage their memory. + // The caller has to provide and manage it instead. + + // Parse a slice header, returning it in |*shdr|. |*nalu| must be set to + // the NALU returned from AdvanceToNextNALU() and corresponding to |*shdr|. + Result ParseSliceHeader(const H264NALU& nalu, H264SliceHeader* shdr); + + // Parse a SEI message, returning it in |*sei_msg|, provided and managed + // by the caller. + Result ParseSEI(H264SEIMessage* sei_msg); + + private: + // Move the stream pointer to the beginning of the next NALU, + // i.e. pointing at the next start code. + // Return true if a NALU has been found. + // If a NALU is found: + // - its size in bytes is returned in |*nalu_size| and includes + // the start code as well as the trailing zero bits. + // - the size in bytes of the start code is returned in |*start_code_size|. + bool LocateNALU(off_t* nalu_size, off_t* start_code_size); + + // Exp-Golomb code parsing as specified in chapter 9.1 of the spec. + // Read one unsigned exp-Golomb code from the stream and return in |*val|. + Result ReadUE(int* val); + + // Read one signed exp-Golomb code from the stream and return in |*val|. + Result ReadSE(int* val); + + // Parse scaling lists (see spec). + Result ParseScalingList(int size, int* scaling_list, bool* use_default); + Result ParseSPSScalingLists(H264SPS* sps); + Result ParsePPSScalingLists(const H264SPS& sps, H264PPS* pps); + + // Parse optional VUI parameters in SPS (see spec). + Result ParseVUIParameters(H264SPS* sps); + // Set |hrd_parameters_present| to true only if they are present. + Result ParseAndIgnoreHRDParameters(bool* hrd_parameters_present); + + // Parse reference picture lists' modifications (see spec). + Result ParseRefPicListModifications(H264SliceHeader* shdr); + Result ParseRefPicListModification(int num_ref_idx_active_minus1, + H264ModificationOfPicNum* ref_list_mods); + + // Parse prediction weight table (see spec). + Result ParsePredWeightTable(const H264SPS& sps, H264SliceHeader* shdr); + + // Parse weighting factors (see spec). + Result ParseWeightingFactors(int num_ref_idx_active_minus1, + int chroma_array_type, + int luma_log2_weight_denom, + int chroma_log2_weight_denom, + H264WeightingFactors* w_facts); + + // Parse decoded reference picture marking information (see spec). + Result ParseDecRefPicMarking(H264SliceHeader* shdr); + + // Pointer to the current NALU in the stream. + const uint8_t* stream_; + + // Bytes left in the stream after the current NALU. + off_t bytes_left_; + + H264BitReader br_; + + // PPSes and SPSes stored for future reference. + typedef std::map SPSById; + typedef std::map PPSById; + SPSById active_SPSes_; + PPSById active_PPSes_; + + // Ranges of encrypted bytes in the buffer passed to + // SetEncryptedStream(). + Ranges encrypted_ranges_; + + DISALLOW_COPY_AND_ASSIGN(H264Parser); + }; + +} // namespace media + +#endif // MEDIA_FILTERS_H264_PARSER_H_ diff --git a/src/H264/h264_poc.cpp b/src/H264/h264_poc.cpp new file mode 100644 index 00000000..451ca944 --- /dev/null +++ b/src/H264/h264_poc.cpp @@ -0,0 +1,232 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include "Util/logger.h" +#include +#include "macros.h" +#include "h264_parser.h" +#include "h264_poc.h" + +using namespace ZL::Util; + +namespace media { + + H264POC::H264POC() { + Reset(); + } + + H264POC::~H264POC() { + } + + void H264POC::Reset() { + // It shouldn't be necessary to reset these values, but doing so will improve + // reproducibility for buggy streams. + ref_pic_order_cnt_msb_ = 0; + ref_pic_order_cnt_lsb_ = 0; + prev_frame_num_ = 0; + prev_frame_num_offset_ = 0; + } + + // Check if a slice includes memory management control operation 5, which + // results in some |pic_order_cnt| state being cleared. + static bool HasMMCO5(const media::H264SliceHeader& slice_hdr) { + // Require that the frame actually has memory management control operations. + if (slice_hdr.nal_ref_idc == 0 || + slice_hdr.idr_pic_flag || + !slice_hdr.adaptive_ref_pic_marking_mode_flag) { + return false; + } + + for (size_t i = 0; i < arraysize(slice_hdr.ref_pic_marking); i++) { + int32_t op = slice_hdr.ref_pic_marking[i].memory_mgmnt_control_operation; + if (op == 5) + return true; + + // Stop at the end of the list. + if (op == 0) + return false; + } + + // Should not get here, the list is always zero terminated. + return false; + } + + bool H264POC::ComputePicOrderCnt( + const H264SPS* sps, + const H264SliceHeader& slice_hdr, + int32_t *pic_order_cnt) { + if (slice_hdr.field_pic_flag) { + DebugL << "Interlaced frames are not supported"; + return false; + } + + bool mmco5 = HasMMCO5(slice_hdr); + int32_t max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); + int32_t max_pic_order_cnt_lsb = + 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + // Check for invalid (including duplicate) |frame_num| values. All cases are + // treated as gaps, which is to say that nothing is done. (Gaps don't affect + // POC computation.) + if (!slice_hdr.idr_pic_flag && + slice_hdr.frame_num != (prev_frame_num_ + 1) % max_frame_num) { + if (!sps->gaps_in_frame_num_value_allowed_flag){ + //WarnL << "Invalid gap in frame_num"; + } + } + + // Based on T-REC-H.264 8.2.1, "Decoding process for picture order + // count", available from http://www.itu.int/rec/T-REC-H.264. + // + // Reorganized slightly from spec pseudocode to handle MMCO5 when storing + // state instead of when loading it. + switch (sps->pic_order_cnt_type) { + case 0: { + int32_t prev_pic_order_cnt_msb = ref_pic_order_cnt_msb_; + int32_t prev_pic_order_cnt_lsb = ref_pic_order_cnt_lsb_; + + // For an IDR picture, clear the state. + if (slice_hdr.idr_pic_flag) { + prev_pic_order_cnt_msb = 0; + prev_pic_order_cnt_lsb = 0; + } + + // 8-3. Derive |pic_order_cnt_msb|, accounting for wrapping which is + // detected when |pic_order_cnt_lsb| increases or decreases by at + // least half of its maximum. + int32_t pic_order_cnt_msb; + if ((slice_hdr.pic_order_cnt_lsb < prev_pic_order_cnt_lsb) && + (prev_pic_order_cnt_lsb - slice_hdr.pic_order_cnt_lsb >= + max_pic_order_cnt_lsb / 2)) { + pic_order_cnt_msb = prev_pic_order_cnt_msb + max_pic_order_cnt_lsb; + } else if ((slice_hdr.pic_order_cnt_lsb > prev_pic_order_cnt_lsb) && + (slice_hdr.pic_order_cnt_lsb - prev_pic_order_cnt_lsb > + max_pic_order_cnt_lsb / 2)) { + pic_order_cnt_msb = prev_pic_order_cnt_msb - max_pic_order_cnt_lsb; + } else { + pic_order_cnt_msb = prev_pic_order_cnt_msb; + } + + // 8-4, 8-5. Derive |top_field_order_count| and |bottom_field_order_cnt| + // (assuming no interlacing). + int32_t top_foc = pic_order_cnt_msb + slice_hdr.pic_order_cnt_lsb; + int32_t bottom_foc = top_foc + slice_hdr.delta_pic_order_cnt_bottom; + *pic_order_cnt = std::min(top_foc, bottom_foc); + + // Store state. + prev_frame_num_ = slice_hdr.frame_num; + if (slice_hdr.nal_ref_idc != 0) { + if (mmco5) { + ref_pic_order_cnt_msb_ = 0; + ref_pic_order_cnt_lsb_ = top_foc; + } else { + ref_pic_order_cnt_msb_ = pic_order_cnt_msb; + ref_pic_order_cnt_lsb_ = slice_hdr.pic_order_cnt_lsb; + } + } + + break; + } + + case 1: { + // 8-6. Derive |frame_num_offset|. + int32_t frame_num_offset; + if (slice_hdr.idr_pic_flag) + frame_num_offset = 0; + else if (prev_frame_num_ > slice_hdr.frame_num) + frame_num_offset = prev_frame_num_offset_ + max_frame_num; + else + frame_num_offset = prev_frame_num_offset_; + + // 8-7. Derive |abs_frame_num|. + int32_t abs_frame_num; + if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0) + abs_frame_num = frame_num_offset + slice_hdr.frame_num; + else + abs_frame_num = 0; + + if (slice_hdr.nal_ref_idc == 0 && abs_frame_num > 0) + abs_frame_num--; + + // 8-9. Derive |expected_pic_order_cnt| (the |pic_order_cnt| indicated + // by the cycle described in the SPS). + int32_t expected_pic_order_cnt = 0; + if (abs_frame_num > 0) { + // 8-8. Derive pic_order_cnt_cycle_cnt and + // frame_num_in_pic_order_cnt_cycle. + // Moved inside 8-9 to avoid division when this check is not done. + if (sps->num_ref_frames_in_pic_order_cnt_cycle == 0) { + ErrorL << "Invalid num_ref_frames_in_pic_order_cnt_cycle"; + return false; + } + + // H264Parser checks that num_ref_frames_in_pic_order_cnt_cycle < 255. + int32_t pic_order_cnt_cycle_cnt = + (abs_frame_num - 1) / sps->num_ref_frames_in_pic_order_cnt_cycle; + int32_t frame_num_in_pic_order_cnt_cycle = + (abs_frame_num - 1) % sps->num_ref_frames_in_pic_order_cnt_cycle; + + // 8-9 continued. + expected_pic_order_cnt = pic_order_cnt_cycle_cnt * + sps->expected_delta_per_pic_order_cnt_cycle; + for (int32_t i = 0; i <= frame_num_in_pic_order_cnt_cycle; i++) + expected_pic_order_cnt += sps->offset_for_ref_frame[i]; + } + if (slice_hdr.nal_ref_idc == 0) + expected_pic_order_cnt += sps->offset_for_non_ref_pic; + + // 8-10. Derive |top_field_order_cnt| and |bottom_field_order_cnt| + // (assuming no interlacing). + int32_t top_foc = expected_pic_order_cnt + slice_hdr.delta_pic_order_cnt0; + int32_t bottom_foc = top_foc + sps->offset_for_top_to_bottom_field + + slice_hdr.delta_pic_order_cnt1; + *pic_order_cnt = std::min(top_foc, bottom_foc); + + // Store state. + prev_frame_num_ = slice_hdr.frame_num; + prev_frame_num_offset_ = frame_num_offset; + if (mmco5) + prev_frame_num_offset_ = 0; + + break; + } + + case 2: { + // 8-11. Derive |frame_num_offset|. + int32_t frame_num_offset; + if (slice_hdr.idr_pic_flag) + frame_num_offset = 0; + else if (prev_frame_num_ > slice_hdr.frame_num) + frame_num_offset = prev_frame_num_offset_ + max_frame_num; + else + frame_num_offset = prev_frame_num_offset_; + + // 8-12, 8-13. Derive |temp_pic_order_count| (it's always the + // |pic_order_cnt|, regardless of interlacing). + if (slice_hdr.idr_pic_flag) + *pic_order_cnt = 0; + else if (slice_hdr.nal_ref_idc == 0) + *pic_order_cnt = 2 * (frame_num_offset + slice_hdr.frame_num) - 1; + else + *pic_order_cnt = 2 * (frame_num_offset + slice_hdr.frame_num); + + // Store state. + prev_frame_num_ = slice_hdr.frame_num; + prev_frame_num_offset_ = frame_num_offset; + if (mmco5) + prev_frame_num_offset_ = 0; + + break; + } + + default: + ErrorL << "Invalid pic_order_cnt_type: " << sps->pic_order_cnt_type; + return false; + } + + return true; + } + +} // namespace media diff --git a/src/H264/h264_poc.h b/src/H264/h264_poc.h new file mode 100644 index 00000000..a83990d1 --- /dev/null +++ b/src/H264/h264_poc.h @@ -0,0 +1,45 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_VIDEO_H264_POC_H_ +#define MEDIA_VIDEO_H264_POC_H_ + +#include +#include "macros.h" + +using namespace std; + +namespace media { + + struct H264SPS; + struct H264SliceHeader; + + class MEDIA_EXPORT H264POC { + public: + H264POC(); + ~H264POC(); + + // Compute the picture order count for a slice, storing the result into + // |*pic_order_cnt|. + bool ComputePicOrderCnt( + const H264SPS* sps, + const H264SliceHeader& slice_hdr, + int32_t* pic_order_cnt); + + // Reset computation state. It's best (although not strictly required) to call + // this after a seek. + void Reset(); + + private: + int32_t ref_pic_order_cnt_msb_; + int32_t ref_pic_order_cnt_lsb_; + int32_t prev_frame_num_; + int32_t prev_frame_num_offset_; + + DISALLOW_COPY_AND_ASSIGN(H264POC); + }; + +} // namespace media + +#endif // MEDIA_VIDEO_H264_POC_H_ diff --git a/src/H264/macros.h b/src/H264/macros.h new file mode 100644 index 00000000..3570ae9e --- /dev/null +++ b/src/H264/macros.h @@ -0,0 +1,100 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains macros and macro-like constructs (e.g., templates) that +// are commonly used throughout Chromium source. (It may also contain things +// that are closely related to things that are commonly used that belong in this +// file.) + +#ifndef BASE_MACROS_H_ +#define BASE_MACROS_H_ + +#include // For size_t. + +// Put this in the declarations for a class to be uncopyable. +#define DISALLOW_COPY(TypeName) \ +TypeName(const TypeName&) = delete + +// Put this in the declarations for a class to be unassignable. +#define DISALLOW_ASSIGN(TypeName) \ +void operator=(const TypeName&) = delete + +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ +TypeName(const TypeName&) = delete; \ +void operator=(const TypeName&) = delete + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ +TypeName() = delete; \ +DISALLOW_COPY_AND_ASSIGN(TypeName) + +// The arraysize(arr) macro returns the # of elements in an array arr. The +// expression is a compile-time constant, and therefore can be used in defining +// new arrays, for example. If you use arraysize on a pointer by mistake, you +// will get a compile-time error. For the technical details, refer to +// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template char (&ArraySizeHelper(T (&array)[N]))[N]; +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +// Used to explicitly mark the return value of a function as unused. If you are +// really sure you don't want to do anything with the return value of a function +// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example: +// +// std::unique_ptr my_var = ...; +// if (TakeOwnership(my_var.get()) == SUCCESS) +// ignore_result(my_var.release()); +// +template +inline void ignore_result(const T&) { +} + +// The following enum should be used only as a constructor argument to indicate +// that the variable has static storage class, and that the constructor should +// do nothing to its state. It indicates to the reader that it is legal to +// declare a static instance of the class, provided the constructor is given +// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a +// static variable that has a constructor or a destructor because invocation +// order is undefined. However, IF the type can be initialized by filling with +// zeroes (which the loader does for static variables), AND the destructor also +// does nothing to the storage, AND there are no virtual methods, then a +// constructor declared as +// explicit MyClass(base::LinkerInitialized x) {} +// and invoked as +// static MyClass my_variable_name(base::LINKER_INITIALIZED); +namespace base { + enum LinkerInitialized { LINKER_INITIALIZED }; + + // Use these to declare and define a static local variable (static T;) so that + // it is leaked so that its destructors are not called at exit. If you need + // thread-safe initialization, use base/lazy_instance.h instead. +#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \ +static type& name = *new type arguments + +} // base + +#define MEDIA_EXPORT + +#include +#include "Util/logger.h" +using namespace ZL::Util; + +#define DCHECK(x) if(!(x)) { ErrorL << "DCHECK " << #x < (y))) { ErrorL << "DCHECK_GT:" << #x << #y << endl; } +#define DCHECK_GE(x,y) if(!((x) >= (y))) { ErrorL << "DCHECK_GE:" << #x << #y << endl; } +#define DCHECK_LT(x,y) if(!((x) < (y))) { ErrorL << "DCHECK_LT:" << #x << #y << endl; } +#define NOTREACHED() ErrorL << "NOTREACHED" << endl; + + +#endif // BASE_MACROS_H_ diff --git a/src/H264/ranges.cpp b/src/H264/ranges.cpp new file mode 100644 index 00000000..53640d70 --- /dev/null +++ b/src/H264/ranges.cpp @@ -0,0 +1,9 @@ +// +// ranges.cpp +// MediaPlayer +// +// Created by xzl on 2017/1/13. +// Copyright © 2017年 jizan. All rights reserved. +// + +#include "ranges.h" diff --git a/src/H264/ranges.h b/src/H264/ranges.h new file mode 100644 index 00000000..99cc7399 --- /dev/null +++ b/src/H264/ranges.h @@ -0,0 +1,154 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_RANGES_H_ +#define MEDIA_BASE_RANGES_H_ + +#include +#include + +#include +#include +#include + +using namespace std; + +namespace media { + + // Ranges allows holding an ordered list of ranges of [start,end) intervals. + // The canonical example use-case is holding the list of ranges of buffered + // bytes or times in a