提交 c5624aad authored 作者: blu's avatar blu

init

上级 d4952ba1
...@@ -5,16 +5,20 @@ CFLAGS = -g -Wall ...@@ -5,16 +5,20 @@ CFLAGS = -g -Wall
LIBOPENCV = `pkg-config opencv --cflags --libs` LIBOPENCV = `pkg-config opencv --cflags --libs`
LIBFFMPEG = `pkg-config libavformat libavutil libavcodec --cflags --libs` LIBFFMPEG = `pkg-config libavformat libavutil libavcodec --cflags --libs`
LIBS=
.PHONY: all .PHONY: all
all: libzmq rtspr all: libzmq evmgr evpusher
.PHONY: libzmq .PHONY: libzmq
libzmq: libzmq:
cd vendor/libzmq && [ -f $(CURDIR)/vendor/lib/pkgconfig/libzmq.pc ] || ./autogen.sh && ./configure --prefix=$(CURDIR)/vendor cd vendor/libzmq && [ ! -f $(CURDIR)/vendor/lib/pkgconfig/libzmq.pc ] || ./autogen.sh && ./configure --prefix=$(CURDIR)/vendor
cd vendor/libzmq && make -j 4 && make install cd vendor/libzmq && make -j 4 && make install
rtspr: rtsp-relay.cpp evmgr: evmgr.cpp inc/common.hpp inc/tinythread.hpp
$(CPP) $(CPPFLAGS) -o rtspr rtsp-relay.cpp $(LIBFFMPEG) `pkg-config --cflags --libs vendor/lib/pkgconfig/libzmq.pc` $(CPP) $(CPPFLAGS) -o evmgr evmgr.cpp $(LIBFFMPEG) `pkg-config --cflags --libs vendor/lib/pkgconfig/libzmq.pc` $(LIBS)
evpusher: evpusher.cpp inc/common.hpp inc/tinythread.hpp
$(CPP) $(CPPFLAGS) -o evpusher evpusher.cpp $(LIBFFMPEG) `pkg-config --cflags --libs vendor/lib/pkgconfig/libzmq.pc` $(LIBS)
rtsp: rtsp.cpp rtsp: rtsp.cpp
$(CPP) $(CFLAGS) -o rtsp rtsp.cpp $(LIBFFMPEG) $(CPP) $(CFLAGS) -o rtsp rtsp.cpp $(LIBFFMPEG)
...@@ -26,4 +30,7 @@ mux: demuxing_decoding.c ...@@ -26,4 +30,7 @@ mux: demuxing_decoding.c
$(CC) $(CFLAGS) -o mux demuxing_decoding.c $(LIBFFMPEG) $(CC) $(CFLAGS) -o mux demuxing_decoding.c $(LIBFFMPEG)
clean: clean:
rm -fr rtsp cvprog mux rtspr *.dSYM mkdir -p vendor/lib/pkgconfig/bak
\ No newline at end of file mv vendor/lib/pkgconfig/*.pc vendor/lib/pkgconfig/bak
rm -fr evmgr evpusher *.dSYM vendor/lib/pkgconfig/*.pc
cd vendor/libzmq && make clean
\ No newline at end of file
#pragma GCC diagnostic ignored "-Wunused-private-field"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <stdlib.h>
#include <string>
#include <thread>
#include <iostream>
#include <chrono>
#include <future>
#ifdef OS_LINUX
#include <filesystem>
namespace fs = std::filesystem;
#endif
#include "vendor/include/zmq.h"
#include "inc/json.hpp"
#include "inc/blockingconcurrentqueue.hpp"
#include "inc/tinythread.hpp"
#include "inc/common.hpp"
using namespace std;
using json = nlohmann::json;
using namespace moodycamel;
class PacketPusher: public TinyThread {
private:
// 2M
#define MAX_ZMQ_MSG_SIZE 1204 * 1024 * 2
void *pSubContext = NULL; // for packets relay
void *pSubscriber = NULL;
int setupMq()
{
teardownMq();
int ret = 0;
pSubContext = zmq_ctx_new();
pSubscriber = zmq_socket(pSubContext, ZMQ_SUB);
ret = zmq_setsockopt(pSubscriber, ZMQ_SUBSCRIBE, "", 0);
if(ret != 0) {
logThrow(NULL, AV_LOG_FATAL, "failed connect to pub");
}
ret = zmq_connect(pSubscriber, "tcp://172.31.0.96:5556");
if(ret != 0) {
logThrow(NULL, AV_LOG_FATAL, "failed create sub");
}
return 0;
}
int teardownMq()
{
if(pSubscriber != NULL) {
zmq_close(pSubscriber);
}
if(pSubscriber != NULL) {
zmq_ctx_destroy(pSubscriber);
}
return 0;
}
protected:
void run()
{
int ret = 0;
bool bStopSig = false;
zmq_msg_t msg;
av_log_set_level(AV_LOG_DEBUG);
while (true) {
if(checkStop() == true) {
bStopSig = true;
break;
}
int ret =zmq_msg_init(&msg);
if(ret != 0) {
av_log(NULL, AV_LOG_ERROR, "failed to init zmq msg");
continue;
}
ret = zmq_recvmsg(pSubscriber, &msg, 0);
if(ret < 0) {
av_log(NULL, AV_LOG_ERROR, "failed to recv zmq msg");
continue;
}
av_log(NULL, AV_LOG_DEBUG, "msg size: %d, %d", ret, zmq_msg_size(&msg));
zmq_msg_close(&msg);
}
if(!bStopSig && ret < 0) {
//TOOD: reconnect
av_log(NULL, AV_LOG_ERROR, "TODO: failed, reconnecting");
}else {
av_log(NULL, AV_LOG_INFO, "exit on command");
}
}
public:
PacketPusher()
{
setupMq();
}
~PacketPusher()
{
teardownMq();
}
};
int main(int argc, char *argv[]){
PacketPusher pusher;
pusher.join();
}
\ No newline at end of file
#ifndef __COMMON_H__
#define __COMMON_H__
extern "C" {
#include <libavformat/avformat.h>
}
#include <libavutil/timestamp.h>
#undef av_err2str
#define av_err2str(errnum) av_make_error_string((char*)__builtin_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum)
void logThrow(void * avcl, int lvl, const char *fmt, ...)
{
(void) avcl;
(void) lvl;
va_list args;
va_start( args, fmt );
av_log(NULL, AV_LOG_FATAL, fmt, args);
va_end( args );
throw fmt;
}
namespace PacketSerializer {
int encode(AVPacket &pkt, char **bytes) {
int wholeSize = 4 + pkt.size;
if(pkt.side_data_elems != 0) {
for(int i = 0; i < pkt.side_data_elems; i++) {
wholeSize += pkt.side_data[i].size + 8;
}
}else{
wholeSize +=4;
}
wholeSize += 8 * 5 + 4;
*bytes = (char*)malloc(wholeSize);
// data
memcpy(*bytes, &(pkt.size), 4);
memcpy(*bytes, pkt.data, pkt.size);
//side data
memcpy(*bytes, &(pkt.side_data_elems), 4);
if(pkt.side_data_elems != 0) {
for(int i = 0; i < pkt.side_data_elems; i++) {
memcpy(*bytes, &(pkt.side_data[i].size), 4);
memcpy(*bytes, pkt.side_data[i].data, pkt.side_data[i].size);
memcpy(*bytes, &(pkt.side_data[i].type), 4);
}
}else{
wholeSize +=4;
}
// other properties
memcpy(*bytes, &(pkt.pts), 8);
memcpy(*bytes, &(pkt.dts), 8);
memcpy(*bytes, &(pkt.pos), 8);
memcpy(*bytes, &(pkt.duration), 8);
memcpy(*bytes, &(pkt.convergence_duration), 8);
memcpy(*bytes, &(pkt.flags), 4);
av_log_set_level(AV_LOG_DEBUG);
av_log(NULL, AV_LOG_DEBUG, "\n\n\npkt origin size %d, serialized size: %d, elems:%d\n\n\n", pkt.size, wholeSize, pkt.side_data_elems);
return wholeSize;
}
AVPacket *decode(char * bytes) {
// allocate packet mem on heap
AVPacket *pkt = (AVPacket*)malloc(sizeof(AVPacket));
int got = 0;
memcpy(&(pkt->size), bytes, 4);
got += 4;
av_new_packet(pkt, pkt->size);
memcpy(pkt->data, bytes + got, pkt->size);
got += pkt->size;
memcpy(&pkt->side_data_elems, bytes + got, 4);
got += 4;
for(int i = 0; i < pkt->side_data_elems; i++) {
memcpy(&(pkt->side_data[i].size), bytes+got, 4);
got += 4;
memcpy(pkt->side_data[i].data,bytes + got ,pkt->side_data[i].size);
got += pkt->side_data[i].size;
memcpy(&(pkt->side_data[i].type), bytes + got, 4);
got += 4;
}
// props
memcpy(&(pkt->pts), bytes + got, 8);
got += 8;
memcpy(&(pkt->dts), bytes + got, 8);
got += 8;
memcpy(&(pkt->pos), bytes + got, 8);
got += 8;
memcpy(&(pkt->duration), bytes + got, 8);
got += 8;
memcpy(&(pkt->convergence_duration), bytes + got, 8);
got += 8;
memcpy(&(pkt->flags), bytes + got, 4);
got += 4;
return pkt;
}
}
void mqPacketFree(void *data, void*hint) {
free(data);
}
#endif
#ifndef __TINY_THREAD__
#define __TINY_THREAD__
#include <thread>
#include <iostream>
#include <chrono>
#include <future>
using namespace std;
class TinyThread {
std::promise<void> exitSignal;
std::future<void> futureObj;
int state = 0;
thread th;
protected:
// Task need to provide defination for this function
// It will be called by thread function
virtual void run() = 0;
public:
TinyThread() :
futureObj(exitSignal.get_future())
{
}
TinyThread(TinyThread && obj) : exitSignal(std::move(obj.exitSignal)), futureObj(std::move(obj.futureObj))
{
std::cout << "Move Constructor is called" << std::endl;
}
TinyThread & operator=(TinyThread && obj)
{
std::cout << "Move Assignment is called" << std::endl;
exitSignal = std::move(obj.exitSignal);
futureObj = std::move(obj.futureObj);
return *this;
}
// Thread function to be executed by thread
private:
void _run()
{
if(state == 0) {
th =thread([&]() {
this->run();
});
state = 1;
}
}
public:
//Checks if thread is requested to stop
bool checkStop()
{
// checks if value in future object is available
if (futureObj.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout)
return false;
return true;
}
// Request the thread to stop by setting value in promise object
void stop()
{
exitSignal.set_value();
}
void join()
{
_run();
if(th.joinable()) {
th.join();
}
}
void detach()
{
_run();
if(th.joinable()) {
th.detach();
}
}
};
#endif
\ No newline at end of file
#pragma GCC diagnostic ignored "-Wunused-private-field"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <stdlib.h>
#include <string>
#include <thread>
#include <iostream>
#include <chrono>
#include <future>
#ifdef OS_LINUX
#include <filesystem>
namespace fs = std::filesystem;
#endif
#include "vendor/include/zmq.h"
#include "inc/json.hpp"
#include "inc/blockingconcurrentqueue.hpp"
#include "inc/tinythread.hpp"
#include "inc/common.hpp"
using namespace std;
using json = nlohmann::json;
using namespace moodycamel;
class PacketPusher: public TinyThread {
private:
void *pPubContext = NULL; // for packets publishing
void *pPublisher = NULL;
AVFormatContext *pAVFormatInput = NULL, *pAVFormatRemux = NULL;
string urlIn;
int *streamList = NULL, numStreams = 0;
public:
PacketPusher(string urlIn):urlIn(urlIn){
setupMq();
}
~PacketPusher(){
}
protected:
// Function to be executed by thread function
void run()
{
int ret = 0;
if ((ret = avformat_open_input(&pAVFormatInput, urlIn.c_str(), NULL, NULL)) < 0) {
logThrow(NULL, AV_LOG_FATAL, "Could not open input file '%s'", urlIn.c_str());
}
if ((ret = avformat_find_stream_info(pAVFormatInput, NULL)) < 0) {
logThrow(NULL, AV_LOG_FATAL, "Failed to retrieve input stream information");
}
pAVFormatInput->flags = AVFMT_FLAG_NOBUFFER | AVFMT_FLAG_FLUSH_PACKETS;
numStreams = pAVFormatInput->nb_streams;
int *streamList = (int *)av_mallocz_array(numStreams, sizeof(*streamList));
if (!streamList) {
ret = AVERROR(ENOMEM);
logThrow(NULL, AV_LOG_FATAL, "failed create avformatcontext for output: %s", av_err2str(AVERROR(ENOMEM)));
}
// find all video & audio streams for remuxing
int i = 0, streamIdx = 0;
for (; i < pAVFormatInput->nb_streams; i++) {
AVStream *out_stream;
AVStream *in_stream = pAVFormatInput->streams[i];
AVCodecParameters *in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
streamList[i] = -1;
continue;
}
streamList[i] = streamIdx++;
out_stream = avformat_new_stream(pAVFormatRemux, NULL);
if (!out_stream) {
logThrow(NULL, AV_LOG_FATAL, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
}
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
if (ret < 0) {
logThrow(NULL, AV_LOG_FATAL, "Failed to copy codec parameters\n");
}
}
while (checkStop() == false) {
AVStream *in_stream, *out_stream;
AVPacket packet;
ret = av_read_frame(pAVFormatInput, &packet);
if (ret < 0)
break;
in_stream = pAVFormatInput->streams[packet.stream_index];
if (packet.stream_index >= numStreams || streamList[packet.stream_index] < 0) {
av_packet_unref(&packet);
continue;
}
packet.stream_index = streamList[packet.stream_index];
out_stream = pAVFormatRemux->streams[packet.stream_index];
/* copy packet */
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
packet.pos = -1;
ret = av_interleaved_write_frame(pAVFormatRemux, &packet);
if (ret < 0) {
logThrow(NULL, AV_LOG_FATAL, "Error muxing packet\n");
break;
}
av_packet_unref(&packet);
}
av_write_trailer(pAVFormatRemux);
std::cout << "Pusher Start" << std::endl;
// Check if thread is requested to stop ?
while (checkStop() == false) {
std::cout << "Doing Some Work" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Task End" << std::endl;
}
int setupMq()
{
teardownMq();
pPubContext = zmq_ctx_new();
pPublisher = zmq_socket(pPubContext, ZMQ_PUB);
int rc = zmq_bind(pPublisher, "tcp://*:5556");
if(rc != 0) {
logThrow(NULL, AV_LOG_FATAL, "failed create pub");
}
return 0;
}
int teardownMq()
{
if(pPublisher != NULL) {
zmq_close(pPublisher);
}
if(pPubContext != NULL) {
zmq_ctx_destroy(pPubContext);
}
return 0;
}
};
class VideoProcessor {
private:
#define SECS_SLICE (60*5/2)
AVFormatContext *pAVFormatInput = NULL, *pAVFormatRemux = NULL;
AVCodec *pCodec = NULL;
AVDictionary *pOptsRemux = NULL, *pOptsInput = NULL, *pOptsOutput = NULL;
int idxVideo = -1, idxAudio = -1, numStreams = 0, numSlices = 6, secsSlice = SECS_SLICE;
int *streamList = NULL;
bool bPush = true, bRecord = false;
string urlIn, urlOut, pathSlice;
unordered_map<string, string> envParams = unordered_map<string, string>();
// mq
void *pRepContext = NULL; // for msg from edge gateway
void *pReqContext = NULL; // for msg to edge gateway
private:
void setupParams()
{
char *tmp = getenv("URL_IN");
urlIn = (tmp == NULL?string(""): string(tmp));
tmp= getenv("URL_OUT");
urlOut = (tmp == NULL?string(""): string(tmp));
tmp = getenv("SLICE_NUM");
numSlices = (tmp == NULL?6:atoi(tmp));
if(numSlices <=2) {
numSlices = 6;
}
tmp = getenv("SLICE_PATH");
pathSlice = (tmp == NULL?string("slices"):string(tmp));
// OSX XCode doesn't ship with the filesystem header as of version 10.x
#ifdef __LINUX___
if (!fs::exists(pathSlice.c_str())) {
if (!fs::create_directory(pathSlice.c_str())) {
logThrow(NULL, AV_LOG_FATAL, "can't create directory: %s", pathSlice.c_str());
exit(1);
}
fs::permissions(pathSlice.c_str(), fs::perms::all);
}
#endif
tmp = getenv("PUSH");
bPush = (tmp == NULL?false: (string(tmp) == string("false")?false:true));
tmp = getenv("SLICE_SECS");
secsSlice = (tmp == NULL?SECS_SLICE:atoi(tmp));
if(secsSlice < SECS_SLICE) {
secsSlice = SECS_SLICE;
}
if(urlIn == "" or urlOut == "") {
logThrow(NULL, AV_LOG_FATAL, "no input/output url");
exit(1);
}
}
int setupStreams()
{
PacketPusher pusher(urlIn);
pusher.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
pusher.stop();
std::this_thread::sleep_for(std::chrono::milliseconds(9993000));
int ret = 0, i, streamIdx = 0;
// if ((ret = avformat_open_input(&pAVFormatInput, urlIn.c_str(), NULL, NULL)) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Could not open input file '%s'", urlIn.c_str());
// }
// if ((ret = avformat_find_stream_info(pAVFormatInput, NULL)) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Failed to retrieve input stream information");
// }
// pAVFormatInput->flags = AVFMT_FLAG_NOBUFFER | AVFMT_FLAG_FLUSH_PACKETS;
// ret = avformat_alloc_output_context2(&pAVFormatRemux, NULL, "rtsp", urlOut.c_str());
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed create avformatcontext for output: %s", av_err2str(ret));
// }
// numStreams = pAVFormatInput->nb_streams;
// streamList = (int *)av_mallocz_array(numStreams, sizeof(*streamList));
// if (!streamList) {
// ret = AVERROR(ENOMEM);
// logThrow(NULL, AV_LOG_FATAL, "failed create avformatcontext for output: %s", av_err2str(AVERROR(ENOMEM)));
// }
// // find all video & audio streams for remuxing
// for (i = 0; i < pAVFormatInput->nb_streams; i++) {
// AVStream *out_stream;
// AVStream *in_stream = pAVFormatInput->streams[i];
// AVCodecParameters *in_codecpar = in_stream->codecpar;
// if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
// in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
// in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
// streamList[i] = -1;
// continue;
// }
// streamList[i] = streamIdx++;
// out_stream = avformat_new_stream(pAVFormatRemux, NULL);
// if (!out_stream) {
// logThrow(NULL, AV_LOG_FATAL, "Failed allocating output stream\n");
// ret = AVERROR_UNKNOWN;
// }
// ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Failed to copy codec parameters\n");
// }
// }
// av_dump_format(pAVFormatRemux, 0, urlOut.c_str(), 1);
// // find best video stream
// idxVideo = av_find_best_stream(pAVFormatInput, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0);
// if(idxVideo < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed find best video stream");
// }
// if (!(pAVFormatRemux->oformat->flags & AVFMT_NOFILE)) {
// logThrow(NULL, AV_LOG_FATAL, "Failed allocating output stream\n");
// ret = avio_open2(&pAVFormatRemux->pb, urlOut.c_str(), AVIO_FLAG_WRITE, NULL, &pOptsRemux);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Could not open output file '%s'", urlOut.c_str());
// }
// }
// // rtsp tcp
// if(av_dict_set(&pOptsRemux, "rtsp_transport", "tcp", 0) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed set output pOptsRemux");
// ret = AVERROR_UNKNOWN;
// }
// ret = avformat_write_header(pAVFormatRemux, &pOptsRemux);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Error occurred when opening output file\n");
// }
// while (1) {
// AVStream *in_stream, *out_stream;
// AVPacket packet;
// ret = av_read_frame(pAVFormatInput, &packet);
// if (ret < 0)
// break;
// in_stream = pAVFormatInput->streams[packet.stream_index];
// if (packet.stream_index >= numStreams || streamList[packet.stream_index] < 0) {
// av_packet_unref(&packet);
// continue;
// }
// packet.stream_index = streamList[packet.stream_index];
// out_stream = pAVFormatRemux->streams[packet.stream_index];
// /* copy packet */
// packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
// packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
// packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
// packet.pos = -1;
// ret = av_interleaved_write_frame(pAVFormatRemux, &packet);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Error muxing packet\n");
// break;
// }
// av_packet_unref(&packet);
// }
// av_write_trailer(pAVFormatRemux);
return ret;
}
public:
// ctor
VideoProcessor()
{
setupParams();
setupStreams();
}
// dtor
~VideoProcessor()
{
avformat_close_input(&pAVFormatInput);
/* close output */
if (pAVFormatRemux && !(pAVFormatRemux->oformat->flags & AVFMT_NOFILE))
avio_closep(&pAVFormatRemux->pb);
avformat_free_context(pAVFormatRemux);
av_freep(&streamList);
}
};
int main(int argc, char **argv)
{
auto vp = VideoProcessor();
// AVFormatContext *pAVFormatInput = NULL, *pAVFormatRemux = NULL;
// AVPacket packet;
// AVCodec *pCodec = NULL;
// AVDictionary *pOptsRemux = NULL, *pOptsInput = NULL, *pOptsOutput = NULL;
// (void) pOptsInput;
// const char *urlInput, *urlOutput;
// int ret, i, idxVideo;
// int streamIdx = 0;
// int *streamList = NULL;
// int numStreams = 0;
// if (argc != 3) {
// printf("usage: <cmd> rtsp_in rtsp_out\n");
// return -1;
// }
// urlInput = argv[1];
// urlOutput = argv[2];
// if ((ret = avformat_open_input(&pAVFormatInput, urlInput, NULL, NULL)) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Could not open input file '%s'", urlInput);
// goto end;
// }
// if ((ret = avformat_find_stream_info(pAVFormatInput, NULL)) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Failed to retrieve input stream information");
// goto end;
// }
// ret = avformat_alloc_output_context2(&pAVFormatRemux, NULL, "rtsp", urlOutput);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed create avformatcontext for output: %s", av_err2str(ret));
// goto end;
// }
// numStreams = pAVFormatInput->nb_streams;
// streamList = (int *)av_mallocz_array(numStreams, sizeof(*streamList));
// if (!streamList) {
// ret = AVERROR(ENOMEM);
// goto end;
// }
// // find all video & audio streams for remuxing
// for (i = 0; i < pAVFormatInput->nb_streams; i++) {
// AVStream *out_stream;
// AVStream *in_stream = pAVFormatInput->streams[i];
// AVCodecParameters *in_codecpar = in_stream->codecpar;
// if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
// in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
// in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
// streamList[i] = -1;
// continue;
// }
// streamList[i] = streamIdx++;
// out_stream = avformat_new_stream(pAVFormatRemux, NULL);
// if (!out_stream) {
// logThrow(NULL, AV_LOG_FATAL, "Failed allocating output stream\n");
// ret = AVERROR_UNKNOWN;
// goto end;
// }
// ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Failed to copy codec parameters\n");
// goto end;
// }
// }
// av_dump_format(pAVFormatRemux, 0, urlOutput, 1);
// // find best video stream
// idxVideo = av_find_best_stream(pAVFormatInput, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0);
// if(idxVideo < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed find best video stream");
// goto end;
// }
// // unless it's a no file (we'll talk later about that) write to the disk (FLAG_WRITE)
// // but basically it's a way to save the file to a buffer so you can store it
// // wherever you want.
// if (!(pAVFormatRemux->oformat->flags & AVFMT_NOFILE)) {
// logThrow(NULL, AV_LOG_FATAL, "Failed allocating output stream\n");
// ret = avio_open2(&pAVFormatRemux->pb, urlOutput, AVIO_FLAG_WRITE, NULL, &pOptsRemux);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Could not open output file '%s'", urlOutput);
// goto end;
// }
// }
// // if (mp4Fragmented) {
// // av_dict_set(&pOptsRemux, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0);
// // }
// // rtsp tcp
// if(av_dict_set(&pOptsRemux, "rtsp_transport", "tcp", 0) < 0) {
// logThrow(NULL, AV_LOG_FATAL, "failed set output pOptsRemux");
// ret = AVERROR_UNKNOWN;
// goto end;
// }
// ret = avformat_write_header(pAVFormatRemux, &pOptsRemux);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Error occurred when opening output file\n");
// goto end;
// }
// while (1) {
// AVStream *in_stream, *out_stream;
// ret = av_read_frame(pAVFormatInput, &packet);
// if (ret < 0)
// break;
// in_stream = pAVFormatInput->streams[packet.stream_index];
// if (packet.stream_index >= numStreams || streamList[packet.stream_index] < 0) {
// av_packet_unref(&packet);
// continue;
// }
// packet.stream_index = streamList[packet.stream_index];
// out_stream = pAVFormatRemux->streams[packet.stream_index];
// /* copy packet */
// packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
// packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
// packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
// packet.pos = -1;
// ret = av_interleaved_write_frame(pAVFormatRemux, &packet);
// if (ret < 0) {
// logThrow(NULL, AV_LOG_FATAL, "Error muxing packet\n");
// break;
// }
// av_packet_unref(&packet);
// }
// av_write_trailer(pAVFormatRemux);
// end:
// avformat_close_input(&pAVFormatInput);
// /* close output */
// if (pAVFormatRemux && !(pAVFormatRemux->oformat->flags & AVFMT_NOFILE))
// avio_closep(&pAVFormatRemux->pb);
// avformat_free_context(pAVFormatRemux);
// av_freep(&streamList);
// if (ret < 0 && ret != AVERROR_EOF) {
// logThrow(NULL, AV_LOG_FATAL, "Error occurred: %s\n", av_err2str(ret));
// return 1;
// }
// return 0;
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论