Commit fc95a69a authored by Linshizhi's avatar Linshizhi

StreamContext with native supported protocol pass tests.

parent 04b6acf6
...@@ -99,5 +99,17 @@ add_custom_command(TARGET FFmpegProtoTestCases PRE_BUILD ...@@ -99,5 +99,17 @@ add_custom_command(TARGET FFmpegProtoTestCases PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/resources/ $<TARGET_FILE_DIR:FFmpegProtoTestCases>/resources) ${CMAKE_SOURCE_DIR}/resources/ $<TARGET_FILE_DIR:FFmpegProtoTestCases>/resources)
add_test_with_ffmpeg(MovMemProtoTestCases
${SRCs}/basic/container/list.c
${SRCs}/proto.c
${SRCs}/MovMem/mm.c
${Tests}/mmTestCases.c)
add_test_with_ffmpeg(StreamContextTestCases
${SRCs}/basic/container/list.c
${SRCs}/proto.c
${SRCs}/MovMem/mm.c
${SRCs}/streamContext.c
${Tests}/streamContextTestCases.c)
endif() endif()
#include "mm.h" #include "mm.h"
#include "../basic/utils.h" #include "../basic/utils.h"
/*****************************************************************************/
/* Local Helper Functions */
/*****************************************************************************/
static int mmRead(void *priv, uint8_t *buf, int size) { static int mmRead(void *priv, uint8_t *buf, int size) {
MMProto *proto = priv; MMProto *proto = priv;
MemMovContext *context = mmContext(proto); MemMovContext *context = mmc(proto);
List *buffers = mmprotoBuffer(proto); List *buffers = mmpBuffer(proto);
if ((priv == NULL || buf == NULL || size < 0)) { if ((priv == NULL || buf == NULL || size < 0)) {
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
// No Datas // No Datas
if (mmContextEmpty(context) && listEmpty(buffers)) { if (mmcEmpty(context) && listEmpty(buffers)) {
return AVERROR(EAGAIN); return AVERROR(EAGAIN);
} }
if (mmContextEmpty(context)) { if (mmcEmpty(context)) {
BufferInfo *info = listPop(buffers); BufferInfo *info = listPop(buffers);
assignBufferMMContext(context, info->buffer, info->size); mmcAssignBuf(context, info->buffer, info->size);
free(info);
} }
if (mmContextIsEOF(context)) { if (mmcIsEOF(context)) {
return AVERROR_EOF; return AVERROR_EOF;
} }
int sizeToRead = MIN(mmContextRemain(context), size); int sizeToRead = MIN(mmcRemain(context), size);
memcpy(buf, mmContextBuffer(context), sizeToRead); memcpy(buf, mmcBuffer(context), sizeToRead);
// Update MemMovContext // Update MemMovContext
mmContextSetPos(context, mmContextPos(context)+sizeToRead); mmcSetPos(context, mmcPos(context)+sizeToRead);
mmContextSetRemain(context, mmContextRemain(context)-sizeToRead); mmcSetRemain(context, mmcRemain(context)-sizeToRead);
// Do cleanning // Do cleanning
if (mmContextEmpty(context)) resetMMContext(context); if (mmcEmpty(context)) mmcReset(context);
return sizeToRead == 0 ? AVERROR(EAGAIN) : sizeToRead; return sizeToRead == 0 ? AVERROR(EAGAIN) : sizeToRead;
} }
...@@ -43,6 +50,19 @@ static int mmWrite(void *priv, uint8_t *buf, int size) { ...@@ -43,6 +50,19 @@ static int mmWrite(void *priv, uint8_t *buf, int size) {
abort(); abort();
} }
static void bufferInfoDestructor(void *val) {
BufferInfo *v = val;
if (v == NULL) return;
if (v->buffer) free(v->buffer);
free(v);
}
/*****************************************************************************/
/* Member Functions */
/*****************************************************************************/
MMProto* createMMProto(void) { MMProto* createMMProto(void) {
MMProto *p = (MMProto*)malloc(sizeof(MMProto)); MMProto *p = (MMProto*)malloc(sizeof(MMProto));
memset(p, 0, sizeof(MMProto)); memset(p, 0, sizeof(MMProto));
...@@ -54,21 +74,58 @@ MMProto* createMMProto(void) { ...@@ -54,21 +74,58 @@ MMProto* createMMProto(void) {
setSeekMethod(&p->Base, NULL); setSeekMethod(&p->Base, NULL);
p->buffer = createList(); p->buffer = createList();
listSetDestructor(p->buffer, bufferInfoDestructor);
return p; return p;
} }
void assignBufferMMContext(MemMovContext *mmc, uint8_t *buffer, int size) { void mmcAssignBuf(MemMovContext *mmc, uint8_t *buffer, int size) {
mmc->buffer = buffer; mmc->buffer = buffer;
mmc->pos = buffer; mmc->pos = buffer;
mmc->remain = size; mmc->remain = size;
} }
void resetMMContext(MemMovContext *mm) { void mmcReset(MemMovContext *mm) {
free(mm->buffer); free(mm->buffer);
mm->buffer = NULL; mm->buffer = NULL;
mm->pos = NULL; mm->pos = NULL;
mm->remain = 0; mm->remain = 0;
} }
void destroyMMProto(MMProto **p) {
MMProto *p_ = *p;
// Destruct Base
destroyProto_(&p_->Base);
// Clean MovMem specifi resources
destroyList(&p_->buffer);
mmcReset(&p_->context);
free(p_);
*p = NULL;
}
void mmpPush(MMProto *mm, uint8_t *packets, int size) {
BufferInfo *info = (BufferInfo*)malloc(sizeof(BufferInfo));
info->buffer = packets;
info->size = size;
listPush(mm->buffer, info);
}
BufferInfo* mmpPop(MMProto *mm) {
BufferInfo *info = listPop(mm->buffer);
if (info == NULL) return NULL;
return info;
}
void destroyBufferInfo(BufferInfo **info) {
bufferInfoDestructor((void**)info);
}
...@@ -25,23 +25,26 @@ typedef struct MMProto { ...@@ -25,23 +25,26 @@ typedef struct MMProto {
/* Member function implement as macros */ /* Member function implement as macros */
#define mmprotoBuffer(MM) ((MM)->buffer) #define mmpBuffer(MM) ((MM)->buffer)
#define mmContext(MM) (&(MM)->context) #define mmc(MM) (&(MM)->context)
#define mmContextEmpty(MMC) ((MMC)->remain == 0) #define mmcEmpty(MMC) ((MMC)->remain == 0)
#define mmContextIsEOF(MMC) ((MMC)->buffer == NULL) #define mmcIsEOF(MMC) ((MMC)->buffer == NULL)
#define mmContextRemain(MMC) ((MMC)->remain) #define mmcRemain(MMC) ((MMC)->remain)
#define mmContextBuffer(MMC) ((MMC)->buffer) #define mmcBuffer(MMC) ((MMC)->buffer)
#define mmContextPos(MMC) ((MMC)->pos) #define mmcPos(MMC) ((MMC)->pos)
#define mmContextSetPos(MMC, POS) ((MMC)->pos = (POS)) #define mmcSetPos(MMC, POS) ((MMC)->pos = (POS))
#define mmContextRemain(MMC) ((MMC)->remain) #define mmcRemain(MMC) ((MMC)->remain)
#define mmContextSetRemain(MMC, REMAIN) ((MMC)->remain = (REMAIN)) #define mmcSetRemain(MMC, REMAIN) ((MMC)->remain = (REMAIN))
#define mmpEmpty(MM) (listSize((MM)->buffer) == 0)
/* Prototypes */ /* Prototypes */
MMProto* createMMProto(void); MMProto* createMMProto(void);
void pushMMProto(MMProto *mm, uint8_t *packets); void destroyMMProto(MMProto**);
uint8_t* popMMProto(MMProto *mm); void mmpPush(MMProto *mm, uint8_t *packets, int size);
void assignBufferMMContext(MemMovContext *mm, uint8_t *buffer, int size); BufferInfo* mmpPop(MMProto *mm);
void resetMMContext(MemMovContext *mm); void mmcAssignBuf(MemMovContext *mm, uint8_t *buffer, int size);
void mmcReset(MemMovContext *mm);
void destroyBufferInfo(BufferInfo**);
......
...@@ -15,10 +15,7 @@ Proto* createProto(ReadFunc rf, WriteFunc wf, SeekFunc sf, void *priv) { ...@@ -15,10 +15,7 @@ Proto* createProto(ReadFunc rf, WriteFunc wf, SeekFunc sf, void *priv) {
void destroyProto(Proto **p) { void destroyProto(Proto **p) {
Proto *p_ = *p; Proto *p_ = *p;
if (p_->ctx) { destroyProto_(p_);
av_free(p_->ctx->buffer);
avio_context_free(&p_->ctx);
}
free(p_); free(p_);
*p = NULL; *p = NULL;
...@@ -31,11 +28,20 @@ Proto createProto_(ReadFunc rf, WriteFunc wf, SeekFunc sf, void *priv) { ...@@ -31,11 +28,20 @@ Proto createProto_(ReadFunc rf, WriteFunc wf, SeekFunc sf, void *priv) {
.write = wf, .write = wf,
.seek = sf, .seek = sf,
.priv = priv, .priv = priv,
.ctx = NULL,
}; };
return p; return p;
} }
void destroyProto_(Proto *p) {
if (p == NULL) return;
if (p->ctx) {
av_free(p->ctx->buffer);
avio_context_free(&p->ctx);
}
}
AVIOContext* proto2AVIO(Proto *p, size_t bufSize) { AVIOContext* proto2AVIO(Proto *p, size_t bufSize) {
unsigned char *buffer = (unsigned char *)av_malloc(bufSize); unsigned char *buffer = (unsigned char *)av_malloc(bufSize);
......
...@@ -8,6 +8,8 @@ typedef int (*ReadFunc)(void *priv, uint8_t *buf, int size); ...@@ -8,6 +8,8 @@ typedef int (*ReadFunc)(void *priv, uint8_t *buf, int size);
typedef int (*WriteFunc)(void *priv, uint8_t *buf, int size); typedef int (*WriteFunc)(void *priv, uint8_t *buf, int size);
typedef int64_t (*SeekFunc)(void *opaque, int64_t offset, int whence); typedef int64_t (*SeekFunc)(void *opaque, int64_t offset, int whence);
typedef void (*ProtoDestructor)(void**);
typedef struct Proto { typedef struct Proto {
int (*read)(void *priv, uint8_t *buf, int size); int (*read)(void *priv, uint8_t *buf, int size);
int (*write)(void *priv, uint8_t *buf, int size); int (*write)(void *priv, uint8_t *buf, int size);
...@@ -23,11 +25,13 @@ typedef struct Proto { ...@@ -23,11 +25,13 @@ typedef struct Proto {
#define read(P, buf, size) ((P)->read((P)->priv, (buf), (size))) #define read(P, buf, size) ((P)->read((P)->priv, (buf), (size)))
#define write(P, buf, size) ((P)->write((P)->priv, (buf), (size))) #define write(P, buf, size) ((P)->write((P)->priv, (buf), (size)))
#define seek(P, offset, whence) ((P)->seek((P)->priv, (offset), (whence))) #define seek(P, offset, whence) ((P)->seek((P)->priv, (offset), (whence)))
#define Super(DerivedPtr) ((Proto*)(DerivedPtr))
/* Prototypes */ /* Prototypes */
Proto* createProto(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv); Proto* createProto(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv);
void destroyProto(Proto**); void destroyProto(Proto**);
Proto createProto_(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv); Proto createProto_(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv);
void destroyProto_(Proto*);
AVIOContext* proto2AVIO(Proto *p, size_t bufSize); AVIOContext* proto2AVIO(Proto *p, size_t bufSize);
......
...@@ -26,6 +26,14 @@ CTEST_TEARDOWN(LIST_TEST) { ...@@ -26,6 +26,14 @@ CTEST_TEARDOWN(LIST_TEST) {
destroyList(&data->l); destroyList(&data->l);
} }
CTEST2(LIST_TEST, RELEASE_DATAS_REMAIN_IN_LIST) {
int *val = NULL;
for (int i = 0; i < 1000; ++i) {
val = (int*)malloc(sizeof(int));
listPush(data->l, val);
}
}
CTEST2(LIST_TEST, PUSH) { CTEST2(LIST_TEST, PUSH) {
int *val = NULL; int *val = NULL;
......
#include "ctest.h" #include "ctest.h"
#include "MovMem/mm.h" #include "MovMem/mm.h"
#include "basic/container/list.h" #include "basic/container/list.h"
void setPacket(uint8_t *p, int size) {
for (int i = 0; i < size; ++i) {
p[i] = i % (int)(exp2(8) -1);
}
}
void verifyPacket(uint8_t *p, int size) {
for (int i = 0; i < size; ++i)
ASSERT_TRUE(p[i] == i % (int)(exp2(8)-1));
}
CTEST_DATA(MMProto_Test) {
MMProto *proto;
List *list;
};
CTEST_SETUP(MMProto_Test) {
data->proto = createMMProto();
data->list = createList();
}
CTEST_TEARDOWN(MMProto_Test) {
destroyList(&data->list);
destroyMMProto(&data->proto);
}
CTEST2(MMProto_Test, READ_MEMS) {
uint8_t *packet;
const int PACKET_SIZE = exp2(8);
size_t total = 0;
const int BUFFER_SIZE = PACKET_SIZE;
uint8_t *buffer = (uint8_t*)malloc(BUFFER_SIZE);
for (int i = 0; i < 1000; ++i) {
packet = (uint8_t*)malloc(PACKET_SIZE);
setPacket(packet, PACKET_SIZE);
mmpPush(data->proto, packet, PACKET_SIZE);
total += PACKET_SIZE;
}
for (int i = 0; i < 1000; ++i) {
read(Super(data->proto), buffer, BUFFER_SIZE);
verifyPacket(buffer, BUFFER_SIZE);
}
free(buffer);
ASSERT_TRUE(mmpEmpty(data->proto));
}
CTEST2(MMProto_Test, READ_EMPTY) {
uint8_t *buffer = (uint8_t*)malloc(1024);
int ret = read(Super(data->proto), buffer, 1024);
ASSERT_EQUAL(AVERROR(EAGAIN), ret);
free(buffer);
}
CTEST2(MMProto_Test, READ_EOF) {
uint8_t *buffer = (uint8_t*)malloc(1024);
mmpPush(data->proto, NULL, 0);
int ret = read(Super(data->proto), buffer, 1024);
ASSERT_EQUAL(AVERROR_EOF, ret);
free(buffer);
}
CTEST2(MMProto_Test, READ_ZERO) {
uint8_t *buffer = (uint8_t*)malloc(1024);
uint8_t *packet = (uint8_t*)malloc(256);
mmpPush(data->proto, packet, 256);
int ret = read(Super(data->proto), buffer, 0);
ASSERT_EQUAL(AVERROR(EAGAIN), ret);
free(buffer);
}
...@@ -60,6 +60,21 @@ CTEST_TEARDOWN(PROTO_TEST) { ...@@ -60,6 +60,21 @@ CTEST_TEARDOWN(PROTO_TEST) {
destroyProto(&data->proto); destroyProto(&data->proto);
} }
CTEST(PROTO_TEST, STATIC_DESTROY_CASE1) {
Proto *proto = createProto(readFake, writeFake, seekFake, NULL);
destroyProto_(proto);
free(proto);
}
CTEST(PROTO_TEST, STATIC_DESTROY_CASE2) {
Proto *proto = createProto(readFake, writeFake, seekFake, NULL);
proto2AVIO(proto, exp2(12));
destroyProto_(proto);
free(proto);
}
CTEST2(PROTO_TEST, READ_WRITE) { CTEST2(PROTO_TEST, READ_WRITE) {
uint8_t *rBuf, *wBuf; uint8_t *rBuf, *wBuf;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment