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
COMMAND ${CMAKE_COMMAND} -E copy_directory
${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()
#include "mm.h"
#include "../basic/utils.h"
/*****************************************************************************/
/* Local Helper Functions */
/*****************************************************************************/
static int mmRead(void *priv, uint8_t *buf, int size) {
MMProto *proto = priv;
MemMovContext *context = mmContext(proto);
List *buffers = mmprotoBuffer(proto);
MemMovContext *context = mmc(proto);
List *buffers = mmpBuffer(proto);
if ((priv == NULL || buf == NULL || size < 0)) {
return AVERROR(EINVAL);
}
// No Datas
if (mmContextEmpty(context) && listEmpty(buffers)) {
if (mmcEmpty(context) && listEmpty(buffers)) {
return AVERROR(EAGAIN);
}
if (mmContextEmpty(context)) {
if (mmcEmpty(context)) {
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;
}
int sizeToRead = MIN(mmContextRemain(context), size);
memcpy(buf, mmContextBuffer(context), sizeToRead);
int sizeToRead = MIN(mmcRemain(context), size);
memcpy(buf, mmcBuffer(context), sizeToRead);
// Update MemMovContext
mmContextSetPos(context, mmContextPos(context)+sizeToRead);
mmContextSetRemain(context, mmContextRemain(context)-sizeToRead);
mmcSetPos(context, mmcPos(context)+sizeToRead);
mmcSetRemain(context, mmcRemain(context)-sizeToRead);
// Do cleanning
if (mmContextEmpty(context)) resetMMContext(context);
if (mmcEmpty(context)) mmcReset(context);
return sizeToRead == 0 ? AVERROR(EAGAIN) : sizeToRead;
}
......@@ -43,6 +50,19 @@ static int mmWrite(void *priv, uint8_t *buf, int size) {
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 *p = (MMProto*)malloc(sizeof(MMProto));
memset(p, 0, sizeof(MMProto));
......@@ -54,21 +74,58 @@ MMProto* createMMProto(void) {
setSeekMethod(&p->Base, NULL);
p->buffer = createList();
listSetDestructor(p->buffer, bufferInfoDestructor);
return p;
}
void assignBufferMMContext(MemMovContext *mmc, uint8_t *buffer, int size) {
void mmcAssignBuf(MemMovContext *mmc, uint8_t *buffer, int size) {
mmc->buffer = buffer;
mmc->pos = buffer;
mmc->remain = size;
}
void resetMMContext(MemMovContext *mm) {
void mmcReset(MemMovContext *mm) {
free(mm->buffer);
mm->buffer = NULL;
mm->pos = NULL;
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 {
/* Member function implement as macros */
#define mmprotoBuffer(MM) ((MM)->buffer)
#define mmContext(MM) (&(MM)->context)
#define mmContextEmpty(MMC) ((MMC)->remain == 0)
#define mmContextIsEOF(MMC) ((MMC)->buffer == NULL)
#define mmContextRemain(MMC) ((MMC)->remain)
#define mmContextBuffer(MMC) ((MMC)->buffer)
#define mmContextPos(MMC) ((MMC)->pos)
#define mmContextSetPos(MMC, POS) ((MMC)->pos = (POS))
#define mmContextRemain(MMC) ((MMC)->remain)
#define mmContextSetRemain(MMC, REMAIN) ((MMC)->remain = (REMAIN))
#define mmpBuffer(MM) ((MM)->buffer)
#define mmc(MM) (&(MM)->context)
#define mmcEmpty(MMC) ((MMC)->remain == 0)
#define mmcIsEOF(MMC) ((MMC)->buffer == NULL)
#define mmcRemain(MMC) ((MMC)->remain)
#define mmcBuffer(MMC) ((MMC)->buffer)
#define mmcPos(MMC) ((MMC)->pos)
#define mmcSetPos(MMC, POS) ((MMC)->pos = (POS))
#define mmcRemain(MMC) ((MMC)->remain)
#define mmcSetRemain(MMC, REMAIN) ((MMC)->remain = (REMAIN))
#define mmpEmpty(MM) (listSize((MM)->buffer) == 0)
/* Prototypes */
MMProto* createMMProto(void);
void pushMMProto(MMProto *mm, uint8_t *packets);
uint8_t* popMMProto(MMProto *mm);
void assignBufferMMContext(MemMovContext *mm, uint8_t *buffer, int size);
void resetMMContext(MemMovContext *mm);
MMProto* createMMProto(void);
void destroyMMProto(MMProto**);
void mmpPush(MMProto *mm, uint8_t *packets, int size);
BufferInfo* mmpPop(MMProto *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) {
void destroyProto(Proto **p) {
Proto *p_ = *p;
if (p_->ctx) {
av_free(p_->ctx->buffer);
avio_context_free(&p_->ctx);
}
destroyProto_(p_);
free(p_);
*p = NULL;
......@@ -31,11 +28,20 @@ Proto createProto_(ReadFunc rf, WriteFunc wf, SeekFunc sf, void *priv) {
.write = wf,
.seek = sf,
.priv = priv,
.ctx = NULL,
};
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) {
unsigned char *buffer = (unsigned char *)av_malloc(bufSize);
......
......@@ -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 int64_t (*SeekFunc)(void *opaque, int64_t offset, int whence);
typedef void (*ProtoDestructor)(void**);
typedef struct Proto {
int (*read)(void *priv, uint8_t *buf, int size);
int (*write)(void *priv, uint8_t *buf, int size);
......@@ -23,11 +25,13 @@ typedef struct Proto {
#define read(P, buf, size) ((P)->read((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 Super(DerivedPtr) ((Proto*)(DerivedPtr))
/* Prototypes */
Proto* createProto(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv);
void destroyProto(Proto**);
Proto createProto_(ReadFunc rf, WriteFunc wr, SeekFunc sf, void *priv);
void destroyProto_(Proto*);
AVIOContext* proto2AVIO(Proto *p, size_t bufSize);
......
......@@ -26,6 +26,14 @@ CTEST_TEARDOWN(LIST_TEST) {
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) {
int *val = NULL;
......
#include "ctest.h"
#include "MovMem/mm.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) {
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) {
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