diff --git a/app/src/main/cpp/media/Streaming.cpp b/app/src/main/cpp/media/Streaming.cpp index a0bd9b3a..addb2d45 100644 --- a/app/src/main/cpp/media/Streaming.cpp +++ b/app/src/main/cpp/media/Streaming.cpp @@ -156,4 +156,97 @@ void StreamForwarder::processFrame(AVFrame* frame) { frame->width, frame->height); } } -#endif \ No newline at end of file +#endif + + +bool StreamForwarder::initialize(const std::string& input, const std::string& output) { + inputUrl = input; + outputUrl = output; + + if (avformat_open_input(&inputFormatContext, inputUrl.c_str(), nullptr, nullptr) < 0) { + return false; + } + + if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { + cleanup(); + return false; + } + + if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "mpegts", + outputUrl.c_str()) < 0) { + cleanup(); + return false; + } + + return true; +} + +bool StreamForwarder::start() +{ + if (!inputFormatContext || !outputFormatContext) { + return false; + } + + for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++) { + AVStream* inStream = inputFormatContext->streams[i]; + AVStream* outStream = avformat_new_stream(outputFormatContext, + inStream->codec->codec); + + if (!outStream) { + cleanup(); + return false; + } + + if (avcodec_parameters_copy(outStream->codecpar, + inStream->codecpar) < 0) { + cleanup(); + return false; + } + } + + if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + if (avio_open(&outputFormatContext->pb, outputUrl.c_str(), + AVIO_FLAG_WRITE) < 0) { + cleanup(); + return false; + } + } + + if (avformat_write_header(outputFormatContext, nullptr) < 0) { + cleanup(); + return false; + } + + AVPacket packet; + while (!stopRequested && av_read_frame(inputFormatContext, &packet) >= 0) { + av_write_frame(outputFormatContext, &packet); + av_packet_unref(&packet); + } + + av_write_trailer(outputFormatContext); + return true; +} + +bool StreamForwarder::stop() +{ + stopRequested = true; + return true; +} + +bool StreamForwarder::isStreaming() const +{ + return !stopRequested; +} + +void StreamForwarder::cleanup() { + if (inputFormatContext) { + avformat_close_input(&inputFormatContext); + } + + if (outputFormatContext) { + if (!(outputFormatContext->oformat->flags & AVFMT_NOFILE)) { + avio_closep(&outputFormatContext->pb); + } + avformat_free_context(outputFormatContext); + } +} diff --git a/app/src/main/cpp/media/Streaming.h b/app/src/main/cpp/media/Streaming.h index 9819f40f..e4c1fbc1 100644 --- a/app/src/main/cpp/media/Streaming.h +++ b/app/src/main/cpp/media/Streaming.h @@ -7,6 +7,7 @@ #include #include +#include #include @@ -21,9 +22,12 @@ class Streaming { public: virtual ~Streaming() {} - virtual void start() {} - virtual void stop() {} + virtual bool start() { return false; } + virtual bool stop() { return false; } + virtual bool isStreaming() const { return false; } }; + + #if 0 class StreamForwarder : public Streaming { @@ -44,7 +48,35 @@ private: bool openInput(const std::string& inputUrl); bool openOutput(const std::string& outputUrl); void forwardPackets(); + void setFrameCallback(std::function callback); }; #endif + +class StreamForwarder : public Streaming { +private: + AVFormatContext* inputFormatContext; + AVFormatContext* outputFormatContext; + std::string inputUrl; + std::string outputUrl; + +public: + StreamForwarder() : inputFormatContext(nullptr), outputFormatContext(nullptr) {} + + ~StreamForwarder() { + cleanup(); + } + + bool initialize(const std::string& input, const std::string& output); + virtual bool start(); + virtual bool stop(); + virtual bool isStreaming() const; + +private: + void cleanup(); + + bool stopRequested; +}; + + #endif //MICROPHOTO_STREAMING_H