more C++ wrappers
This commit is contained in:
parent
3959e80e36
commit
2a2ab38bf5
@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
project(ffConv)
|
project(ffConv)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -Og")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -O2")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -Og")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -O0")
|
||||||
|
|
||||||
find_package(FFMPEG REQUIRED)
|
find_package(FFMPEG REQUIRED)
|
||||||
include_directories(${FFMPEG_INCLUDE_DIRS})
|
include_directories(${FFMPEG_INCLUDE_DIRS})
|
||||||
@ -11,6 +11,6 @@ link_directories(${FFMPEG_LIBRARY_DIRS})
|
|||||||
|
|
||||||
#message(FATAL_ERROR ${FFMPEG_LIBRARIES})
|
#message(FATAL_ERROR ${FFMPEG_LIBRARIES})
|
||||||
|
|
||||||
set(SOURCE_FILES main.cpp ffcpp/MediaFile.cpp ffcpp/MediaFile.h ffcpp/ffcpp.cpp ffcpp/ffcpp.h ffcpp/Stream.cpp ffcpp/Stream.h ffcpp/Codec.cpp ffcpp/Codec.h ffcpp/Packet.cpp ffcpp/Packet.h)
|
set(SOURCE_FILES main.cpp ffcpp/MediaFile.cpp ffcpp/MediaFile.h ffcpp/ffcpp.cpp ffcpp/ffcpp.h ffcpp/Stream.cpp ffcpp/Stream.h ffcpp/Codec.cpp ffcpp/Codec.h ffcpp/Packet.cpp ffcpp/Packet.h ffcpp/Frame.cpp ffcpp/Frame.h)
|
||||||
add_executable(ffConv ${SOURCE_FILES})
|
add_executable(ffConv ${SOURCE_FILES})
|
||||||
target_link_libraries(ffConv ${FFMPEG_LIBRARIES})
|
target_link_libraries(ffConv ${FFMPEG_LIBRARIES})
|
||||||
@ -83,4 +83,29 @@ namespace ffcpp {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Frame Codec::decode(Packet &packet) {
|
||||||
|
Frame frame;
|
||||||
|
int gotPicture = 0;
|
||||||
|
auto decFunc = (_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO ? avcodec_decode_video2 : avcodec_decode_audio4);
|
||||||
|
|
||||||
|
while(!gotPicture) {
|
||||||
|
int res = decFunc(_codecCtx, frame, &gotPicture, packet);
|
||||||
|
if(res < 0) throw std::runtime_error("cannot decode packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.guessPts();
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet Codec::encode(AVFrame* frame) {
|
||||||
|
Packet packet;
|
||||||
|
int gotPacket = 0;
|
||||||
|
auto encFunc = (_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO ? avcodec_encode_video2 : avcodec_encode_audio2);
|
||||||
|
|
||||||
|
int res = encFunc(_codecCtx, packet, frame, &gotPacket);
|
||||||
|
if(res < 0) throw std::runtime_error("cannot encode frame");
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
#ifndef FFCONV_CODEC_H
|
#ifndef FFCONV_CODEC_H
|
||||||
#define FFCONV_CODEC_H
|
#define FFCONV_CODEC_H
|
||||||
|
|
||||||
|
#include "Packet.h"
|
||||||
|
#include "Frame.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
}
|
}
|
||||||
@ -14,8 +17,8 @@ namespace ffcpp {
|
|||||||
|
|
||||||
class Codec {
|
class Codec {
|
||||||
private:
|
private:
|
||||||
AVCodecContext* _codecCtx;
|
|
||||||
AVCodec* _codec;
|
AVCodec* _codec;
|
||||||
|
AVCodecContext* _codecCtx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Codec();
|
Codec();
|
||||||
@ -35,6 +38,9 @@ namespace ffcpp {
|
|||||||
void setHeight(int height);
|
void setHeight(int height);
|
||||||
void setPixelFormat(AVPixelFormat pixelFormat);
|
void setPixelFormat(AVPixelFormat pixelFormat);
|
||||||
|
|
||||||
|
Frame decode(Packet& packet);
|
||||||
|
Packet encode(AVFrame* frame);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Codec(Codec&& c);
|
Codec(Codec&& c);
|
||||||
Codec& operator=(Codec&& c);
|
Codec& operator=(Codec&& c);
|
||||||
|
|||||||
42
ffcpp/Frame.cpp
Normal file
42
ffcpp/Frame.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "Frame.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace ffcpp {
|
||||||
|
|
||||||
|
Frame::Frame() {
|
||||||
|
_frame = av_frame_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame::Frame(Frame &&frame) {
|
||||||
|
*this = std::move(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame::~Frame() {
|
||||||
|
if(_frame) {
|
||||||
|
av_frame_free(&_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame& Frame::operator=(Frame&& frame) {
|
||||||
|
_frame = frame._frame;
|
||||||
|
frame._frame = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame::operator AVFrame*() {
|
||||||
|
return _frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame::operator const AVFrame*() const {
|
||||||
|
return _frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frame::guessPts() {
|
||||||
|
_frame->pts = av_frame_get_best_effort_timestamp(_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frame::setPictureType(AVPictureType type) {
|
||||||
|
_frame->pict_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
ffcpp/Frame.h
Normal file
29
ffcpp/Frame.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef FFCONV_FRAME_H
|
||||||
|
#define FFCONV_FRAME_H
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ffcpp {
|
||||||
|
|
||||||
|
class Frame {
|
||||||
|
private:
|
||||||
|
AVFrame* _frame;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Frame();
|
||||||
|
Frame(Frame&& frame);
|
||||||
|
~Frame();
|
||||||
|
|
||||||
|
Frame& operator=(Frame&& frame);
|
||||||
|
operator AVFrame*();
|
||||||
|
operator const AVFrame*() const;
|
||||||
|
|
||||||
|
void guessPts();
|
||||||
|
void setPictureType(AVPictureType type);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //FFCONV_FRAME_H
|
||||||
@ -5,6 +5,7 @@
|
|||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
MediaFile::MediaFile(const std::string& src, Mode mode) {
|
MediaFile::MediaFile(const std::string& src, Mode mode) {
|
||||||
|
_formatCtx = nullptr;
|
||||||
_mode = mode;
|
_mode = mode;
|
||||||
if(mode == Mode::Read) {
|
if(mode == Mode::Read) {
|
||||||
int res = avformat_open_input(&_formatCtx, src.c_str(), nullptr, nullptr);
|
int res = avformat_open_input(&_formatCtx, src.c_str(), nullptr, nullptr);
|
||||||
@ -13,8 +14,9 @@ namespace ffcpp {
|
|||||||
res = avformat_find_stream_info(_formatCtx, nullptr);
|
res = avformat_find_stream_info(_formatCtx, nullptr);
|
||||||
throwIfError(res, "cannot find stream info");
|
throwIfError(res, "cannot find stream info");
|
||||||
|
|
||||||
|
_streams.reserve(_formatCtx->nb_streams);
|
||||||
for(size_t i = 0; i < _formatCtx->nb_streams; ++i) {
|
for(size_t i = 0; i < _formatCtx->nb_streams; ++i) {
|
||||||
_streams.push_back(Stream(_formatCtx->streams[i]));
|
_streams.emplace_back(_formatCtx->streams[i]);
|
||||||
}
|
}
|
||||||
} else if(mode == Mode::Write) {
|
} else if(mode == Mode::Write) {
|
||||||
int res = avformat_alloc_output_context2(&_formatCtx, nullptr, nullptr, src.c_str());
|
int res = avformat_alloc_output_context2(&_formatCtx, nullptr, nullptr, src.c_str());
|
||||||
@ -77,6 +79,8 @@ namespace ffcpp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MediaFile::~MediaFile() {
|
MediaFile::~MediaFile() {
|
||||||
|
_streams.clear();
|
||||||
|
|
||||||
if(_mode == Mode::Write) {
|
if(_mode == Mode::Write) {
|
||||||
avformat_free_context(_formatCtx);
|
avformat_free_context(_formatCtx);
|
||||||
} else {
|
} else {
|
||||||
@ -100,6 +104,18 @@ namespace ffcpp {
|
|||||||
return _streams.back();
|
return _streams.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Packet MediaFile::readPacket() {
|
||||||
|
AVPacket packet;
|
||||||
|
packet.data = nullptr;
|
||||||
|
packet.size = 0;
|
||||||
|
int res = av_read_frame(_formatCtx, &packet);
|
||||||
|
return Packet(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
AVMediaType MediaFile::packetType(const Packet &packet) {
|
||||||
|
return _formatCtx->streams[packet.streamIndex()]->codec->codec_type;
|
||||||
|
}
|
||||||
|
|
||||||
void MediaFile::writeHeader() {
|
void MediaFile::writeHeader() {
|
||||||
int res = avformat_write_header(_formatCtx, nullptr);
|
int res = avformat_write_header(_formatCtx, nullptr);
|
||||||
throwIfError(res, "error writing header");
|
throwIfError(res, "error writing header");
|
||||||
@ -109,4 +125,10 @@ namespace ffcpp {
|
|||||||
int res = av_write_trailer(_formatCtx);
|
int res = av_write_trailer(_formatCtx);
|
||||||
throwIfError(res, "error writing trailer");
|
throwIfError(res, "error writing trailer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaFile::writePacket(Packet &packet) {
|
||||||
|
int res = av_interleaved_write_frame(_formatCtx, packet);
|
||||||
|
throwIfError(res, "cannot write frame to output file");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,10 +34,12 @@ namespace ffcpp {
|
|||||||
Stream& videoStream(size_t index = 0);
|
Stream& videoStream(size_t index = 0);
|
||||||
Stream& audioStream(size_t index = 0);
|
Stream& audioStream(size_t index = 0);
|
||||||
Stream& addStream(AVCodecID codecID, int width, int height, AVPixelFormat pixelFormat);
|
Stream& addStream(AVCodecID codecID, int width, int height, AVPixelFormat pixelFormat);
|
||||||
|
Packet readPacket();
|
||||||
|
AVMediaType packetType(const Packet& packet);
|
||||||
|
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeTrailer();
|
void writeTrailer();
|
||||||
|
void writePacket(Packet& packet);
|
||||||
|
|
||||||
~MediaFile();
|
~MediaFile();
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,53 @@
|
|||||||
#include "Packet.h"
|
#include "Packet.h"
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
Packet::Packet() {
|
Packet::Packet() {
|
||||||
_packet.data = nullptr;
|
_packet.data = nullptr;
|
||||||
_packet.size = 0;
|
_packet.size = 0;
|
||||||
|
av_init_packet(&_packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::Packet(AVPacket packet): _packet(packet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::Packet(Packet&& packet) {
|
||||||
|
*this = std::move(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet& Packet::operator=(Packet&& packet) {
|
||||||
|
_packet = packet._packet;
|
||||||
|
packet._packet.size = 0;
|
||||||
|
packet._packet.data = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::~Packet() {
|
||||||
|
if(_packet.data) {
|
||||||
|
av_free_packet(&_packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::operator bool() {
|
||||||
|
return (_packet.data != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet::operator AVPacket*() {
|
||||||
|
return &_packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Packet::streamIndex() const {
|
||||||
|
return _packet.stream_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::setStreamIndex(int index) {
|
||||||
|
_packet.stream_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::rescaleTimestamps(AVRational from, AVRational to) {
|
||||||
|
av_packet_rescale_ts(&_packet, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,18 @@ namespace ffcpp {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Packet();
|
Packet();
|
||||||
|
Packet(AVPacket packet);
|
||||||
|
Packet(Packet&& packet);
|
||||||
|
Packet& operator=(Packet&& packet);
|
||||||
|
~Packet();
|
||||||
|
|
||||||
|
operator bool();
|
||||||
|
operator AVPacket*();
|
||||||
|
|
||||||
|
int streamIndex() const;
|
||||||
|
void setStreamIndex(int index);
|
||||||
|
|
||||||
|
void rescaleTimestamps(AVRational from, AVRational to);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
Stream::Stream(): _stream(nullptr) {
|
Stream::Stream(): _stream(nullptr) {
|
||||||
|
int x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream(AVStream *stream): _stream(stream), _codec(_stream->codec, CodecType::Decoder) {
|
Stream::Stream(AVStream *stream): _stream(stream), _codec(_stream->codec, CodecType::Decoder) {
|
||||||
|
|||||||
107
main.cpp
107
main.cpp
@ -1,23 +1,25 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "ffcpp/ffcpp.h"
|
#include "ffcpp/ffcpp.h"
|
||||||
#include "ffcpp/MediaFile.h"
|
#include "ffcpp/MediaFile.h"
|
||||||
#include "ffcpp/Stream.h"
|
|
||||||
#include "ffcpp/Codec.h"
|
|
||||||
|
|
||||||
extern "C" {
|
constexpr int VIDEO_STREAM_INDEX = 0;
|
||||||
#include <libavformat/avformat.h>
|
constexpr int AUDIO_STREAM_INDEX = 1;
|
||||||
}
|
|
||||||
|
|
||||||
void checkResult(int res, const char* msg) {
|
|
||||||
if(res < 0) {
|
|
||||||
char errStr[260];
|
|
||||||
av_strerror(res, errStr, 260);
|
|
||||||
std::cerr << msg << ": " << errStr << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ff = ffcpp;
|
namespace ff = ffcpp;
|
||||||
|
|
||||||
|
void flushEncoder(ff::MediaFile& file, ff::Codec& encoder, const ff::Stream& inStream, const ff::Stream& outStream, int streamIndex) {
|
||||||
|
if(encoder.capabilities() & AV_CODEC_CAP_DELAY) {
|
||||||
|
while (1) {
|
||||||
|
auto packet = encoder.encode(nullptr);
|
||||||
|
if(!packet) break;
|
||||||
|
|
||||||
|
packet.setStreamIndex(streamIndex);
|
||||||
|
packet.rescaleTimestamps(inStream.timeBase(), outStream.timeBase());
|
||||||
|
file.writePacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
ff::init();
|
ff::init();
|
||||||
ff::MediaFile input(argv[1], ff::Mode::Read);
|
ff::MediaFile input(argv[1], ff::Mode::Read);
|
||||||
@ -31,43 +33,18 @@ int main(int argc, char** argv) {
|
|||||||
ff::Codec& vEncoder = outVStream.codec();
|
ff::Codec& vEncoder = outVStream.codec();
|
||||||
output.writeHeader();
|
output.writeHeader();
|
||||||
|
|
||||||
AVFrame* frame = nullptr;
|
|
||||||
int gotPicture = 0, gotPacket = 0, decodedFrames = 1;
|
|
||||||
int64_t oldPts = 0, oldDts = 0;
|
int64_t oldPts = 0, oldDts = 0;
|
||||||
while(true) {
|
while(auto packet = input.readPacket()) {
|
||||||
AVPacket packet;
|
AVMediaType packetType = input.packetType(packet);
|
||||||
packet.data = nullptr;
|
|
||||||
packet.size = 0;
|
|
||||||
int res = av_read_frame(input, &packet);
|
|
||||||
if(res < 0) break;
|
|
||||||
|
|
||||||
frame = av_frame_alloc();
|
|
||||||
if(!frame) break;
|
|
||||||
|
|
||||||
AVMediaType packetType = ((AVFormatContext*)input)->streams[packet.stream_index]->codec->codec_type;
|
|
||||||
if(packetType == AVMEDIA_TYPE_VIDEO) {
|
if(packetType == AVMEDIA_TYPE_VIDEO) {
|
||||||
res = avcodec_decode_video2(vDecoder, frame, &gotPicture, &packet);
|
auto frame = vDecoder.decode(packet);
|
||||||
if(res < 0) {
|
frame.setPictureType(AV_PICTURE_TYPE_NONE);
|
||||||
av_frame_free(&frame);
|
auto encPacket = vEncoder.encode(frame);
|
||||||
break;
|
if(!encPacket) continue;
|
||||||
}
|
|
||||||
|
|
||||||
if(gotPicture) {
|
encPacket.setStreamIndex(packetType == AVMEDIA_TYPE_VIDEO ? VIDEO_STREAM_INDEX : AUDIO_STREAM_INDEX);
|
||||||
frame->pts = av_frame_get_best_effort_timestamp(frame);
|
|
||||||
frame->pict_type = AV_PICTURE_TYPE_NONE;
|
|
||||||
//std::cout << "decoded frame: " << decodedFrames++ << " pts: " << frame->pts << ", dts: " << frame->pkt_dts << std::endl;
|
|
||||||
|
|
||||||
AVPacket encPacket;
|
|
||||||
encPacket.data = nullptr;
|
|
||||||
encPacket.size = 0;
|
|
||||||
av_init_packet(&encPacket);
|
|
||||||
encPacket.stream_index = 0;
|
|
||||||
|
|
||||||
res = avcodec_encode_video2(vEncoder, &encPacket, frame, &gotPacket);
|
|
||||||
av_frame_free(&frame);
|
|
||||||
if(res < 0) break;
|
|
||||||
if(!gotPacket) continue;
|
|
||||||
|
|
||||||
|
/*
|
||||||
// try to recover in case of bad pts/dts
|
// try to recover in case of bad pts/dts
|
||||||
if(encPacket.pts < encPacket.dts) {
|
if(encPacket.pts < encPacket.dts) {
|
||||||
encPacket.dts = encPacket.pts;
|
encPacket.dts = encPacket.pts;
|
||||||
@ -81,44 +58,14 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
oldPts = encPacket.pts;
|
oldPts = encPacket.pts;
|
||||||
oldDts = encPacket.dts;
|
oldDts = encPacket.dts;
|
||||||
|
*/
|
||||||
|
|
||||||
av_packet_rescale_ts(&encPacket, vStream.timeBase(), outVStream.timeBase());
|
encPacket.rescaleTimestamps(vStream.timeBase(), outVStream.timeBase());
|
||||||
|
output.writePacket(encPacket);
|
||||||
res = av_interleaved_write_frame(output, &encPacket);
|
|
||||||
checkResult(res, "cannot write frame to output file");
|
|
||||||
if(res < 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
av_free_packet(&packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// flush encoder
|
|
||||||
if(vEncoder.capabilities() & AV_CODEC_CAP_DELAY) {
|
|
||||||
std::cout << "flushing encoder" << std::endl;
|
|
||||||
int gotFrame = 0;
|
|
||||||
while (1) {
|
|
||||||
AVPacket encPacket;
|
|
||||||
encPacket.data = nullptr;
|
|
||||||
encPacket.size = 0;
|
|
||||||
av_init_packet(&encPacket);
|
|
||||||
encPacket.stream_index = 0;
|
|
||||||
int res = avcodec_encode_video2(vEncoder, &encPacket, nullptr, &gotFrame);
|
|
||||||
if (res < 0) {
|
|
||||||
std::cout << "avcodec_encode_video2 failed" << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (gotFrame) {
|
|
||||||
//std::cout << "extra frame" << std::endl;
|
|
||||||
av_packet_rescale_ts(&encPacket, vStream.timeBase(), outVStream.timeBase());
|
|
||||||
res = av_interleaved_write_frame(output, &encPacket);
|
|
||||||
checkResult(res, "[flush encoder] cannot write frame to output file");
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flushEncoder(output, vEncoder, vStream, outVStream, VIDEO_STREAM_INDEX);
|
||||||
output.writeTrailer();
|
output.writeTrailer();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user