diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 00000000..93a78cb2
Binary files /dev/null and b/.DS_Store differ
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