ref: 0c35e4385de2f82f3c698885894a4eac862b0ffa
parent: b51963c009a7c3c55fb4d3418ec983a9b15dae10
parent: 4fa810da8b1e6ec63384cacb2d22df6cfee1df96
author: Ethan Hugg <ethanhugg@gmail.com>
date: Wed Feb 12 02:47:16 EST 2014
Merge pull request #281 from jwwang/add_gtests 1. support .c in makefile generator. 2. add test to check C interfaces.
--- a/Makefile
+++ b/Makefile
@@ -64,6 +64,7 @@
#### No user-serviceable parts below this line
ifneq ($(V),Yes)
QUIET_CXX = @printf "CXX\t$@\n";
+ QUIET_CC = @printf "CC\t$@\n";
QUIET_ASM = @printf "ASM\t$@\n";
QUIET_AR = @printf "AR\t$@\n";
QUIET = @
--- a/build/mktargets.py
+++ b/build/mktargets.py
@@ -30,6 +30,14 @@
f.write('\t$(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(' + PREFIX + '_CFLAGS) $(' + PREFIX + '_INCLUDES) -c $(CXX_O) $<\n')
f.write("\n")
+def write_c_rule_pattern(f):
+ src = "$(%s_SRCDIR)/%%.c"%(PREFIX)
+ dst = "$(%s_SRCDIR)/%%.o"%(PREFIX)
+
+ f.write("%s: %s\n"%(dst, src))
+ f.write('\t$(QUIET_CC)$(CC) $(CFLAGS) $(INCLUDES) $(' + PREFIX + '_CFLAGS) $(' + PREFIX + '_INCLUDES) -c $(CXX_O) $<\n')
+ f.write("\n")
+
def write_asm_rule_pattern(f):
src = "$(%s_SRCDIR)/%%.asm"%(PREFIX)
dst = "$(%s_SRCDIR)/%%.o"%(PREFIX)
@@ -42,6 +50,7 @@
def find_sources():
cpp_files = []
asm_files = []
+ c_files = []
print EXCLUDE
for dir in os.walk("."):
for file in dir[2]:
@@ -50,7 +59,9 @@
cpp_files.append(os.path.join(dir[0].strip('./'), file))
if os.path.splitext(file)[1] == '.asm':
asm_files.append(os.path.join(dir[0].strip('./'), file))
- return [cpp_files, asm_files]
+ if os.path.splitext(file)[1] == '.c':
+ c_files.append(os.path.join(dir[0].strip('./'), file))
+ return [cpp_files, asm_files, c_files]
args = parser.parse_args()
@@ -80,7 +91,7 @@
except:
sys.exit(1)
-(cpp, asm) = find_sources()
+(cpp, asm, cfiles) = find_sources()
@@ -91,8 +102,15 @@
for c in cpp:
f.write("\t$(%s_SRCDIR)/%s\\\n"%(PREFIX, c))
f.write("\n")
-f.write("%s_OBJS += $(%s_CPP_SRCS:%s=.o)\n"%(PREFIX, PREFIX, CPP_SUFFIX))
+f.write("%s_OBJS += $(%s_CPP_SRCS:%s=.o)\n\n"%(PREFIX, PREFIX, CPP_SUFFIX))
+if len(cfiles) > 0:
+ f.write("%s_C_SRCS=\\\n"%(PREFIX))
+ for cfile in cfiles:
+ f.write("\t$(%s_SRCDIR)/%s\\\n"%(PREFIX, cfile))
+ f.write("\n")
+ f.write("%s_OBJS += $(%s_C_SRCS:.c=.o)\n\n"%(PREFIX, PREFIX))
+
if len(asm) > 0:
f.write("ifeq ($(USE_ASM), Yes)\n")
f.write("%s_ASM_SRCS=\\\n"%(PREFIX))
@@ -105,6 +123,9 @@
f.write("OBJS += $(%s_OBJS)\n"%PREFIX)
write_cpp_rule_pattern(f)
+
+if len(cfiles) > 0:
+ write_c_rule_pattern(f)
if len(asm) > 0:
write_asm_rule_pattern(f)
--- /dev/null
+++ b/test/c_interface_test.c
@@ -1,0 +1,32 @@
+#include "codec_api.h"
+
+// Cast to this function type to ignore other parameters.
+typedef int (*Func)(void*);
+#define CALL(p, m) (((Func)((*p)->m))(p))
+// Check if the function return an expected number.
+#define CHECK(n, p, m) check(n, CALL(p, m), #m)
+
+typedef void(*CheckFunc)(int, int, const char*);
+
+void CheckEncoderInterface(ISVCEncoder* p, CheckFunc check) {
+ CHECK(1, p, Initialize);
+ CHECK(2, p, Initialize2);
+ CHECK(3, p, Uninitialize);
+ CHECK(4, p, EncodeFrame);
+ CHECK(5, p, EncodeFrame2);
+ CHECK(6, p, EncodeParameterSets);
+ CHECK(7, p, PauseFrame);
+ CHECK(8, p, ForceIntraFrame);
+ CHECK(9, p, SetOption);
+ CHECK(10, p, GetOption);
+}
+
+void CheckDecoderInterface(ISVCDecoder* p, CheckFunc check) {
+ CHECK(1, p, Initialize);
+ CHECK(2, p, Uninitialize);
+ CHECK(3, p, DecodeFrame);
+ CHECK(4, p, DecodeFrame2);
+ CHECK(5, p, DecodeFrameEx);
+ CHECK(6, p, SetOption);
+ CHECK(7, p, GetOption);
+}
--- /dev/null
+++ b/test/cpp_interface_test.cpp
@@ -1,0 +1,116 @@
+#include <gtest/gtest.h>
+#include "codec_api.h"
+
+static void CheckFunctionOrder(int expect, int actual, const char* name) {
+ EXPECT_EQ(expect, actual) << "Wrong function order: " << name;
+}
+
+typedef void(*CheckFunc)(int, int, const char*);
+extern "C" void CheckEncoderInterface(ISVCEncoder* p, CheckFunc);
+extern "C" void CheckDecoderInterface(ISVCDecoder* p, CheckFunc);
+
+// Store the 'this' pointer to verify 'this' is received as expected from C code.
+static void* gThis;
+
+/**
+ * Return a unique number for each virtual function so that we are able to
+ * check if the order of functions in the virtual table is as expected.
+ */
+struct SVCEncoderImpl : public ISVCEncoder {
+ virtual ~SVCEncoderImpl() {}
+ virtual int EXTAPI Initialize(SVCEncodingParam* pParam,
+ const INIT_TYPE kiInitType) {
+ EXPECT_TRUE(gThis == this);
+ return 1;
+ }
+ virtual int EXTAPI Initialize2(void* pParam, const INIT_TYPE kiInitType) {
+ EXPECT_TRUE(gThis == this);
+ return 2;
+ }
+ virtual int EXTAPI Uninitialize() {
+ EXPECT_TRUE(gThis == this);
+ return 3;
+ }
+ virtual int EXTAPI EncodeFrame(const unsigned char* kpSrc,
+ SFrameBSInfo* pBsInfo) {
+ EXPECT_TRUE(gThis == this);
+ return 4;
+ }
+ virtual int EXTAPI EncodeFrame2(const SSourcePicture** kppSrcPicList,
+ int nSrcPicNum, SFrameBSInfo* pBsInfo) {
+ EXPECT_TRUE(gThis == this);
+ return 5;
+ }
+ virtual int EXTAPI EncodeParameterSets(SFrameBSInfo* pBsInfo) {
+ EXPECT_TRUE(gThis == this);
+ return 6;
+ }
+ virtual int EXTAPI PauseFrame(const unsigned char* kpSrc,
+ SFrameBSInfo* pBsInfo) {
+ EXPECT_TRUE(gThis == this);
+ return 7;
+ }
+ virtual int EXTAPI ForceIntraFrame(bool bIDR) {
+ EXPECT_TRUE(gThis == this);
+ return 8;
+ }
+ virtual int EXTAPI SetOption(ENCODER_OPTION eOptionId, void* pOption) {
+ EXPECT_TRUE(gThis == this);
+ return 9;
+ }
+ virtual int EXTAPI GetOption(ENCODER_OPTION eOptionId, void* pOption) {
+ EXPECT_TRUE(gThis == this);
+ return 10;
+ }
+};
+
+struct SVCDecoderImpl : public ISVCDecoder {
+ virtual ~SVCDecoderImpl() {}
+ virtual long EXTAPI Initialize(void* pParam, const INIT_TYPE iInitType) {
+ EXPECT_TRUE(gThis == this);
+ return 1;
+ }
+ virtual long EXTAPI Uninitialize() {
+ EXPECT_TRUE(gThis == this);
+ return 2;
+ }
+ virtual DECODING_STATE EXTAPI DecodeFrame(const unsigned char* pSrc,
+ const int iSrcLen, unsigned char** ppDst, int* pStride,
+ int& iWidth, int& iHeight) {
+ EXPECT_TRUE(gThis == this);
+ return static_cast<DECODING_STATE>(3);
+ }
+ virtual DECODING_STATE EXTAPI DecodeFrame2(const unsigned char* pSrc,
+ const int iSrcLen, void** ppDst, SBufferInfo* pDstInfo) {
+ EXPECT_TRUE(gThis == this);
+ return static_cast<DECODING_STATE>(4);
+ }
+ virtual DECODING_STATE EXTAPI DecodeFrameEx(const unsigned char* pSrc,
+ const int iSrcLen, unsigned char* pDst, int iDstStride,
+ int& iDstLen, int& iWidth, int& iHeight, int& iColorFormat) {
+ EXPECT_TRUE(gThis == this);
+ return static_cast<DECODING_STATE>(5);
+ }
+ virtual long EXTAPI SetOption (DECODER_OPTION eOptionId, void* pOption) {
+ EXPECT_TRUE(gThis == this);
+ return 6;
+ }
+ virtual long EXTAPI GetOption (DECODER_OPTION eOptionId, void* pOption) {
+ EXPECT_TRUE(gThis == this);
+ return 7;
+ }
+};
+
+TEST(ISVCEncoderTest, CheckFunctionOrder) {
+ SVCEncoderImpl* p = new SVCEncoderImpl;
+ gThis = p;
+ CheckEncoderInterface(p, CheckFunctionOrder);
+ delete p;
+}
+
+TEST(ISVCDecoderTest, CheckFunctionOrder) {
+ SVCDecoderImpl* p = new SVCDecoderImpl;
+ gThis = p;
+ CheckDecoderInterface(p, CheckFunctionOrder);
+ delete p;
+}
--- a/test/targets.mk
+++ b/test/targets.mk
@@ -6,11 +6,21 @@
$(CODEC_UNITTEST_SRCDIR)/decoder_test.cpp\
$(CODEC_UNITTEST_SRCDIR)/encoder_test.cpp\
$(CODEC_UNITTEST_SRCDIR)/simple_test.cpp\
+ $(CODEC_UNITTEST_SRCDIR)/./cpp_interface_test.cpp\
CODEC_UNITTEST_OBJS += $(CODEC_UNITTEST_CPP_SRCS:.cpp=.o)
+
+CODEC_UNITTEST_C_SRCS=\
+ $(CODEC_UNITTEST_SRCDIR)/./c_interface_test.c\
+
+CODEC_UNITTEST_OBJS += $(CODEC_UNITTEST_C_SRCS:.c=.o)
+
OBJS += $(CODEC_UNITTEST_OBJS)
$(CODEC_UNITTEST_SRCDIR)/%.o: $(CODEC_UNITTEST_SRCDIR)/%.cpp
$(QUIET_CXX)$(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDES) $(CODEC_UNITTEST_CFLAGS) $(CODEC_UNITTEST_INCLUDES) -c $(CXX_O) $<
+
+$(CODEC_UNITTEST_SRCDIR)/%.o: $(CODEC_UNITTEST_SRCDIR)/%.c
+ $(QUIET_CXX)$(CC) $(CFLAGS) $(INCLUDES) $(CODEC_UNITTEST_CFLAGS) $(CODEC_UNITTEST_INCLUDES) -c $(CXX_O) $<
codec_unittest$(EXEEXT): $(CODEC_UNITTEST_OBJS) $(LIBS) $(CODEC_UNITTEST_LIBS) $(CODEC_UNITTEST_DEPS)
$(QUIET_CXX)$(CXX) $(CXX_LINK_O) $(CODEC_UNITTEST_OBJS) $(CODEC_UNITTEST_LDFLAGS) $(CODEC_UNITTEST_LIBS) $(LDFLAGS) $(LIBS)