Commit f35ec74d authored by Linshizhi's avatar Linshizhi

Stream with native supported protocols pass tests.

parent fc95a69a
#include "streamContext.h"
#ifdef CUSTOM_STREAM_PROBESIZE
#define PROBESIZE CUSTOM_STREAM_PROBESIZE
#else
#define PROBESIZE 50000000
#endif
#define DEFAULT_AVIO_BUFFER_SIZE 4096
#ifdef CUSTOM_AVIO_BUFFER_SIZE
#define AVIO_BUFFER_SIZE CUSTOM_AVIO_BUFFER_SIZE
#else
#define AVIO_BUFFER_SIZE DEFAULT_AVIO_BUFFER_SIZE
#endif
StreamContext* createInStreamContext(
const char *fileName, ProtoInfo ioInfo, int mediaType) {
int ret = 0;
StreamContext *sctx =
(StreamContext*)malloc(sizeof(StreamContext));
memset(sctx, 0, sizeof(StreamContext));
sctx->flags = STREAM_CTX_FLAG_READ;
sctx->fileName = fileName;
sctx->protoInfo = ioInfo;
Proto *io = ioInfo.proto;
AVFormatContext *fmt = NULL;
if (io) {
fmt = avformat_alloc_context();
fmt->pb = proto2AVIO(io, AVIO_BUFFER_SIZE);
fmt->flags &= AVFMT_FLAG_CUSTOM_IO;
}
ret = avformat_open_input(&fmt, io ? NULL : fileName, NULL, NULL);
if (ret < 0) {
goto FAIL;
}
fmt->probesize = PROBESIZE;
ret = avformat_find_stream_info(fmt, NULL);
if (ret < 0) {
goto FAIL;
}
int sIdx = av_find_best_stream(fmt, mediaType, -1, -1, NULL, 0);
if (sIdx == AVERROR_STREAM_NOT_FOUND) {
goto FAIL;
}
sctx->s = fmt->streams[sIdx];
sctx->fmt = fmt;
return sctx;
FAIL:
if (fmt) avformat_close_input(&fmt);
free(sctx);
return NULL;
}
StreamContext* createOutStreamContext(
const char *fileName, ProtoInfo ioInfo, int mediaType) {
int ret = 0;
StreamContext *sctx =
(StreamContext*)malloc(sizeof(StreamContext));
memset(sctx, 0, sizeof(StreamContext));
sctx->fileName = fileName;
sctx->flags = STREAM_CTX_FLAG_WRITE;
sctx->protoInfo = ioInfo;
Proto *io = ioInfo.proto;
AVFormatContext *fmt = NULL;
if (avformat_alloc_output_context2(&fmt, ioInfo.ofmt, NULL, fileName) < 0) {
goto FAIL;
}
if (io) {
fmt->pb = proto2AVIO(io, AVIO_BUFFER_SIZE);
fmt->flags = fmt->flags | AVFMT_FLAG_CUSTOM_IO;
}
sctx->fmt = fmt;
return sctx;
FAIL:
free(sctx);
if (fmt) avformat_free_context(fmt);
return NULL;
}
int streamNewStream(StreamContext *sctx, AVCodecParameters *par) {
AVStream *s = NULL;
AVFormatContext *fmt = streamFormat(sctx);
if (par == NULL)
return STREAM_STATE_ERROR;
s = avformat_new_stream(fmt, NULL);
if (s == NULL) {
return STREAM_STATE_ERROR;
}
if (avcodec_parameters_copy(s->codecpar, par) < 0) {
return STREAM_STATE_ERROR;
}
sctx->s = s;
return STREAM_STATE_OK;
}
int streamWriteHeader(StreamContext *sctx) {
int ret = 0;
AVFormatContext *fmt = sctx->fmt;
if (!sctx->protoInfo.proto) {
ret = avio_open(&fmt->pb, sctx->fileName, AVIO_FLAG_WRITE);
if (ret < 0) {
return STREAM_STATE_ERROR;
}
}
AVDictionary *opts = NULL;
if (avformat_write_header(fmt, &opts) < 0) {
return STREAM_STATE_ERROR;
}
return STREAM_STATE_OK;
}
int streamReadFrame(StreamContext *s, AVPacket *packet) {
return av_read_frame(streamFormat(s), packet);
}
int streamWriteFrame(StreamContext *s, AVPacket *packet) {
return av_write_frame(streamFormat(s), packet);
}
int streamWriteTrailer(StreamContext *s) {
if (av_write_trailer(streamFormat(s)) < 0)
return STREAM_STATE_ERROR;
else
return STREAM_STATE_OK;
}
int streamClose(StreamContext **s_) {
StreamContext *s = *s_;
if (s->flags & STREAM_CTX_FLAG_READ) {
avformat_close_input(&s->fmt);
} else {
if (!s->protoInfo.proto &&
avio_close(s->fmt->pb) < 0) {
return STREAM_STATE_ERROR;
}
avformat_free_context(s->fmt);
}
/* Custom Protocol */
if (s->protoInfo.proto &&
s->protoInfo.destructor) {
s->protoInfo.destructor((void**)&s->protoInfo.proto);
}
free(*s_);
return STREAM_STATE_OK;
}
AVCodecParameters* streamPara(StreamContext *s) {
if (s->s) {
return s->s->codecpar;
} else {
return NULL;
}
}
#include "proto.h"
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#ifndef STREAMCONTEXT_H
#define STREAMCONTEXT_H
typedef enum {
STREAM_CTX_FLAG_READ = 0x01,
STREAM_CTX_FLAG_WRITE = 0x02,
} STREAM_FLAG;
typedef enum {
STREAM_STATE_OK = 0,
STREAM_STATE_ERROR = 1,
} STREAM_STATE;
typedef struct ProtoInfo {
Proto *proto;
ProtoDestructor destructor;
const AVOutputFormat *ofmt;
} ProtoInfo;
typedef struct StreamContext {
AVFormatContext *fmt;
AVStream *s;
const char *fileName;
ProtoInfo protoInfo;
AVIOContext *ioctx;
STREAM_FLAG flags;
} StreamContext;
/* Member function implement as macros */
#define streamFormat(S) ((S)->fmt)
#define streamStream(S) ((S)->s)
#define streamFilename(S) ((S)->fileName)
/* Prototypes */
StreamContext* createInStreamContext(const char *fileName, ProtoInfo io, int mediaType);
StreamContext* createOutStreamContext(const char *fileName, ProtoInfo io, int mediaType);
AVCodecParameters* streamPara(StreamContext *s);
int streamNewStream(StreamContext *s, AVCodecParameters *par);
int streamWriteHeader(StreamContext *s);
int streamReadFrame(StreamContext *s, AVPacket *packet);
int streamWriteFrame(StreamContext *s, AVPacket *packet);
int streamWriteTrailer(StreamContext *s);
int streamClose(StreamContext **s);
#endif /* STREAMCONTEXT_H */
#include <stdbool.h>
#include "ctest.h"
#include "streamContext.h"
#include "MovMem/mm.h"
/*****************************************************************************/
/* StreamContext With offical supported Protocols */
/*****************************************************************************/
CTEST_DATA(STREAM_CONTEXT_TEST) {
const char *ifile;
const char *ofile;
StreamContext *si;
StreamContext *so;
};
CTEST_SETUP(STREAM_CONTEXT_TEST) {
data->ifile = "./resources/small_bunny_1080p_60fps.mp4";
data->ofile = "./resources/small_bunny_1080p_60fps_OUTPUT.mp4";
data->si = createInStreamContext(
data->ifile, (ProtoInfo){ NULL, NULL, NULL }, AVMEDIA_TYPE_VIDEO);
data->so = createOutStreamContext(
data->ofile, (ProtoInfo){NULL, NULL, NULL }, AVMEDIA_TYPE_VIDEO);
}
CTEST_TEARDOWN(STREAM_CONTEXT_TEST) {
streamClose(&data->si);
streamClose(&data->so);
}
CTEST2(STREAM_CONTEXT_TEST, VIDEO_DUPLICATION) {
StreamContext *istream = data->si;
StreamContext *ostream = data->so;
ASSERT_NOT_NULL(istream);
ASSERT_NOT_NULL(ostream);
ASSERT_TRUE(streamNewStream(ostream, streamPara(istream))
== STREAM_STATE_OK);
ASSERT_TRUE(streamWriteHeader(ostream) == STREAM_STATE_OK);
int ret = 0;
AVPacket packet;
while (true) {
ret = streamReadFrame(istream, &packet);
if (ret < 0) {
break;
}
streamWriteFrame(ostream, &packet);
av_packet_unref(&packet);
}
streamWriteTrailer(ostream);
}
/*****************************************************************************/
/* StreamContext With Custom Protocol TestCases */
/*****************************************************************************/
CTEST_DATA(STREAM_CONTEXT_CUSTOM_PROTO) {
char *ifile;
StreamContext *istream;
StreamContext *ostream;
MMProto *mmp;
};
CTEST_SETUP(STREAM_CONTEXT_CUSTOM_PROTO) {
data->ifile = "./resources/small_bunny_1080p_60fps.mp4";
data->mmp = createMMProto();
data->istream = createInStreamContext(
data->ifile, (ProtoInfo){NULL,NULL,NULL}, AVMEDIA_TYPE_VIDEO);
const AVOutputFormat *ofmt = av_guess_format("h264", NULL, NULL);
ASSERT_NOT_NULL(ofmt);
data->ostream = createOutStreamContext(
NULL, (ProtoInfo){(Proto*)data->mmp,(ProtoDestructor)destroyMMProto, ofmt},
AVMEDIA_TYPE_VIDEO);
}
CTEST_TEARDOWN(STREAM_CONTEXT_CUSTOM_PROTO) {
streamClose(&data->istream);
streamClose(&data->ostream);
}
CTEST2(STREAM_CONTEXT_CUSTOM_PROTO, READ_FROM_MOVMEM_PROTO) {
}
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