Latest changes
This commit is contained in:
parent
51c7109193
commit
3da12232a3
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
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 "-std=c++14 -g -O2 -pthread")
|
set(CMAKE_CXX_FLAGS "-std=c++17 -g -O2 -pthread")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -pthread")
|
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -pthread")
|
||||||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
|
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,6 @@ void flushEncoder(ff::MediaFile& file, ff::CodecPtr encoder, ff::StreamPtr inStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
ff::init();
|
|
||||||
ff::MediaFile input(argv[1], ff::Mode::Read);
|
ff::MediaFile input(argv[1], ff::Mode::Read);
|
||||||
ff::MediaFile output(argv[2], ff::Mode::Write);
|
ff::MediaFile output(argv[2], ff::Mode::Write);
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
double aspect = 1.0*vDecoder->width()/vDecoder->height();
|
double aspect = 1.0*vDecoder->width()/vDecoder->height();
|
||||||
int outHeight = (int)(VIDEO_WIDTH/aspect) & ~1;
|
int outHeight = (int)(VIDEO_WIDTH/aspect) & ~1;
|
||||||
auto outVStream = output.addVideoStream(AV_CODEC_ID_H264, VIDEO_WIDTH, outHeight, vDecoder->timeBase(), AV_PIX_FMT_YUV420P);
|
auto outVStream = output.addVideoStream(AV_CODEC_ID_HEVC, VIDEO_WIDTH, outHeight, vDecoder->timeBase(), AV_PIX_FMT_YUV420P);
|
||||||
auto vEncoder = outVStream->codec();
|
auto vEncoder = outVStream->codec();
|
||||||
|
|
||||||
auto outAStream = output.addAudioStream(AV_CODEC_ID_AC3, 2, 44100, AV_SAMPLE_FMT_FLTP);
|
auto outAStream = output.addAudioStream(AV_CODEC_ID_AC3, 2, 44100, AV_SAMPLE_FMT_FLTP);
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
namespace ff = ffcpp;
|
namespace ff = ffcpp;
|
||||||
|
|
||||||
#define WINDOW_WIDTH 640
|
#define WINDOW_WIDTH 1280
|
||||||
#define WINDOW_HEIGHT 480
|
#define WINDOW_HEIGHT 720
|
||||||
|
|
||||||
class SDLWindow: public ff::IVideoSink, public ff::IAudioSink {
|
class SDLWindow: public ff::IVideoSink, public ff::IAudioSink {
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -24,6 +24,8 @@ namespace ffcpp {
|
|||||||
private:
|
private:
|
||||||
AVCodec* _codec;
|
AVCodec* _codec;
|
||||||
AVCodecContext* _codecCtx;
|
AVCodecContext* _codecCtx;
|
||||||
|
mutable FramePtr _tmpFrame;
|
||||||
|
mutable PacketPtr _tmpPacket;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Codec();
|
Codec();
|
||||||
@ -57,7 +59,7 @@ namespace ffcpp {
|
|||||||
void setSampleRate(int sampleRate);
|
void setSampleRate(int sampleRate);
|
||||||
void setStdCompliance(int compliance);
|
void setStdCompliance(int compliance);
|
||||||
|
|
||||||
FramePtr decode(Packet& packet);
|
std::tuple<FramePtr, bool> decode(PacketPtr packet);
|
||||||
Packet encode(FramePtr frame);
|
Packet encode(FramePtr frame);
|
||||||
FramePtr createAudioFrame() const;
|
FramePtr createAudioFrame() const;
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,8 @@ namespace ffcpp {
|
|||||||
StreamPtr audioStream(size_t index = 0);
|
StreamPtr audioStream(size_t index = 0);
|
||||||
StreamPtr addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat = AV_PIX_FMT_NONE);
|
StreamPtr addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat = AV_PIX_FMT_NONE);
|
||||||
StreamPtr addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE);
|
StreamPtr addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE);
|
||||||
Packet readPacket();
|
PacketPtr readPacket();
|
||||||
AVMediaType packetType(const Packet& packet);
|
AVMediaType packetType(const PacketPtr packet);
|
||||||
|
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writeTrailer();
|
void writeTrailer();
|
||||||
|
|||||||
@ -5,8 +5,12 @@ extern "C" {
|
|||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
|
typedef std::shared_ptr<class Packet> PacketPtr;
|
||||||
|
|
||||||
class Packet {
|
class Packet {
|
||||||
private:
|
private:
|
||||||
AVPacket _packet;
|
AVPacket _packet;
|
||||||
|
|||||||
@ -79,6 +79,7 @@ namespace ffcpp {
|
|||||||
private:
|
private:
|
||||||
void decode();
|
void decode();
|
||||||
void displayFrames();
|
void displayFrames();
|
||||||
|
void processFrame(FramePtr frame, AVMediaType type, FrameQueue* queue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillSampleBuffer(uint8_t *data, int length) override;
|
void fillSampleBuffer(uint8_t *data, int length) override;
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace ffcpp {
|
|||||||
|
|
||||||
AVRational timeBase() const;
|
AVRational timeBase() const;
|
||||||
void setTimeBase(AVRational timeBase);
|
void setTimeBase(AVRational timeBase);
|
||||||
int fps() const;
|
float fps() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Stream(Stream&& stream) noexcept;
|
Stream(Stream&& stream) noexcept;
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
#include "ffcpp/Codec.h"
|
#include "ffcpp/Codec.h"
|
||||||
#include "ffcpp/ffcpp.h"
|
#include "ffcpp/ffcpp.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
Codec::Codec(): _codecCtx(nullptr), _codec(nullptr) {
|
Codec::Codec(): _codecCtx(nullptr), _codec(nullptr), _tmpFrame(nullptr), _tmpPacket(nullptr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Codec::Codec(AVCodecID codecId, CodecType type, AVCodecParameters* params /* = nullptr */) {
|
Codec::Codec(AVCodecID codecId, CodecType type, AVCodecParameters* params /* = nullptr */) {
|
||||||
|
_tmpFrame = nullptr;
|
||||||
|
_tmpPacket = nullptr;
|
||||||
|
|
||||||
if(type == CodecType::Encoder) {
|
if(type == CodecType::Encoder) {
|
||||||
_codec = avcodec_find_encoder(codecId);
|
_codec = avcodec_find_encoder(codecId);
|
||||||
} else {
|
} else {
|
||||||
@ -32,6 +36,8 @@ namespace ffcpp {
|
|||||||
Codec::Codec(AVCodecContext *ctx, AVCodec *codec) {
|
Codec::Codec(AVCodecContext *ctx, AVCodec *codec) {
|
||||||
_codecCtx = ctx;
|
_codecCtx = ctx;
|
||||||
_codec = codec;
|
_codec = codec;
|
||||||
|
_tmpFrame = nullptr;
|
||||||
|
_tmpPacket = nullptr;
|
||||||
|
|
||||||
int res = avcodec_open2(_codecCtx, _codec, nullptr);
|
int res = avcodec_open2(_codecCtx, _codec, nullptr);
|
||||||
throwIfError(res, "cannot open codec");
|
throwIfError(res, "cannot open codec");
|
||||||
@ -158,19 +164,25 @@ namespace ffcpp {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FramePtr Codec::decode(Packet &packet) {
|
std::tuple<FramePtr, bool> Codec::decode(PacketPtr packet) {
|
||||||
FramePtr frame = std::make_shared<Frame>();
|
FramePtr frame = _tmpFrame ? _tmpFrame : std::make_shared<Frame>();
|
||||||
|
|
||||||
int res = avcodec_send_packet(_codecCtx, packet);
|
int res = 0;
|
||||||
|
if(packet) {
|
||||||
|
res = avcodec_send_packet(_codecCtx, *packet.get());
|
||||||
if(res < 0) throw std::runtime_error("cannot decode packet");
|
if(res < 0) throw std::runtime_error("cannot decode packet");
|
||||||
|
}
|
||||||
|
|
||||||
while (res >= 0) {
|
|
||||||
res = avcodec_receive_frame(_codecCtx, frame->nativePtr());
|
res = avcodec_receive_frame(_codecCtx, frame->nativePtr());
|
||||||
|
_tmpFrame = res == AVERROR(EAGAIN) ? frame : nullptr;
|
||||||
|
|
||||||
if(res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
|
if(res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
|
||||||
break;
|
if(res == AVERROR_EOF) {
|
||||||
|
std::cout << "================ EOF" << std::endl;
|
||||||
|
}
|
||||||
|
return std::make_tuple(nullptr, true);
|
||||||
} else if(res < 0) {
|
} else if(res < 0) {
|
||||||
throw std::runtime_error("cannot decode packet");
|
throw std::runtime_error("cannot decode packet");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
if(_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
@ -179,7 +191,8 @@ namespace ffcpp {
|
|||||||
frame->guessChannelLayout();
|
frame->guessChannelLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
_tmpPacket = packet;
|
||||||
|
return std::make_tuple(frame, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet Codec::encode(FramePtr frame) {
|
Packet Codec::encode(FramePtr frame) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "ffcpp/ffcpp.h"
|
#include "ffcpp/ffcpp.h"
|
||||||
#include "ffcpp/Frame.h"
|
#include "ffcpp/Frame.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
@ -63,7 +64,7 @@ namespace ffcpp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Frame::guessPts() {
|
void Frame::guessPts() {
|
||||||
_frame->pts = av_frame_get_best_effort_timestamp(_frame);
|
_frame->pts = _frame->best_effort_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::setPictureType(AVPictureType type) {
|
void Frame::setPictureType(AVPictureType type) {
|
||||||
@ -93,7 +94,12 @@ namespace ffcpp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Frame::size() const {
|
int Frame::size() const {
|
||||||
|
if(_frame->nb_samples > 0) {
|
||||||
|
return _frame->nb_samples*_frame->channels*av_get_bytes_per_sample(static_cast<AVSampleFormat>(_frame->format));
|
||||||
|
} else {
|
||||||
|
// TODO: Return something meaningful here
|
||||||
return _frame->pkt_size >= 0 ? _frame->pkt_size : _frame->linesize[0];
|
return _frame->pkt_size >= 0 ? _frame->pkt_size : _frame->linesize[0];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,16 +132,16 @@ namespace ffcpp {
|
|||||||
return sPtr;
|
return sPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet MediaFile::readPacket() {
|
PacketPtr MediaFile::readPacket() {
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
packet.data = nullptr;
|
packet.data = nullptr;
|
||||||
packet.size = 0;
|
packet.size = 0;
|
||||||
int res = av_read_frame(_formatCtx, &packet);
|
int res = av_read_frame(_formatCtx, &packet);
|
||||||
return Packet(packet);
|
return std::make_shared<Packet>(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
AVMediaType MediaFile::packetType(const Packet &packet) {
|
AVMediaType MediaFile::packetType(const PacketPtr packet) {
|
||||||
return _formatCtx->streams[packet.streamIndex()]->codecpar->codec_type;
|
return _formatCtx->streams[packet->streamIndex()]->codecpar->codec_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaFile::writeHeader() {
|
void MediaFile::writeHeader() {
|
||||||
|
|||||||
@ -49,6 +49,9 @@ namespace ffcpp {
|
|||||||
|
|
||||||
auto codec = _aStream->codec().get();
|
auto codec = _aStream->codec().get();
|
||||||
|
|
||||||
|
std::cout << "Input sample rate: " << _aStream->codec()->sampleRate() << std::endl;
|
||||||
|
std::cout << "Input channels: " << _aStream->codec()->channels() << std::endl;
|
||||||
|
|
||||||
_resampler = std::make_shared<Resampler>(_aStream->codec()->channels(),
|
_resampler = std::make_shared<Resampler>(_aStream->codec()->channels(),
|
||||||
_aStream->codec()->channelLayout(),
|
_aStream->codec()->channelLayout(),
|
||||||
_aStream->codec()->sampleRate(),
|
_aStream->codec()->sampleRate(),
|
||||||
@ -78,41 +81,68 @@ namespace ffcpp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::decode() {
|
void Player::decode() {
|
||||||
Packet packet;
|
PacketPtr packet;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
if(_state == PlayerState::Shutdown)
|
if(_state == PlayerState::Shutdown)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
packet = _curMedia ? _curMedia->readPacket() : Packet();
|
packet = _curMedia ? _curMedia->readPacket() : nullptr;
|
||||||
if(!packet) {
|
if(!packet) {
|
||||||
_stateCond.wait(lock, [this]{ return _state == PlayerState::Playing || _state == PlayerState::Shutdown; });
|
_stateCond.wait(lock,
|
||||||
|
[this] { return _state == PlayerState::Playing || _state == PlayerState::Shutdown; });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AVMediaType packetType = _curMedia->packetType(packet);
|
AVMediaType packetType = _curMedia->packetType(packet);
|
||||||
if(packetType == AVMEDIA_TYPE_VIDEO) {
|
if(packetType != AVMEDIA_TYPE_VIDEO && packetType != AVMEDIA_TYPE_AUDIO)
|
||||||
auto frame = _vStream->codec()->decode(packet);
|
continue;
|
||||||
frame = _scaler->scale(frame);
|
|
||||||
|
CodecPtr codec = packetType == AVMEDIA_TYPE_VIDEO ? _vStream->codec() : _aStream->codec();
|
||||||
|
FrameQueue* queue = packetType == AVMEDIA_TYPE_VIDEO ? &_videoFrames : &_audioFrames;
|
||||||
|
|
||||||
|
auto [frame, packedDecoded] = codec->decode(packet);
|
||||||
|
if(!frame) {
|
||||||
|
// Frame partially decoded, but not ready yet
|
||||||
|
// We need next packet to decode rest of the frame
|
||||||
|
continue;
|
||||||
|
} else if(!packedDecoded) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
while(!_videoFrames.try_enqueue(frame)) {
|
processFrame(frame, packetType, queue);
|
||||||
std::cout << "waiting for enqueue video frame" << std::endl;
|
lock.lock();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
|
// Frame is fully decoded, but packet contains more data (at least beginning of the next frame)
|
||||||
|
// So, we need to continue decoding current packet
|
||||||
|
while (!packedDecoded) {
|
||||||
|
// Decoding nullptr means "decode previous cached packet"
|
||||||
|
std::tie(frame, packedDecoded) = _vStream->codec()->decode(nullptr);
|
||||||
|
if(frame) {
|
||||||
|
lock.unlock();
|
||||||
|
processFrame(frame, packetType, queue);
|
||||||
|
lock.lock();
|
||||||
}
|
}
|
||||||
} else if(packetType == AVMEDIA_TYPE_AUDIO) {
|
|
||||||
auto frame = _aStream->codec()->decode(packet);
|
|
||||||
frame = _resampler->resample(frame);
|
|
||||||
lock.unlock();
|
|
||||||
while(!_audioFrames.try_enqueue(frame)) {
|
|
||||||
std::cout << "waiting for enqueue audio frame" << std::endl;
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::processFrame(FramePtr frame, AVMediaType type, FrameQueue* queue) {
|
||||||
|
if(type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
frame = _scaler->scale(frame);
|
||||||
|
} else {
|
||||||
|
frame = _resampler->resample(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!queue->try_enqueue(frame)) {
|
||||||
|
//std::cout << "waiting for enqueue video frame" << std::endl;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Player::displayFrames() {
|
void Player::displayFrames() {
|
||||||
|
int frameCounter = 0;
|
||||||
|
auto start = std::chrono::system_clock::now();
|
||||||
while(true) {
|
while(true) {
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
if(_state == PlayerState::Shutdown)
|
if(_state == PlayerState::Shutdown)
|
||||||
@ -125,20 +155,25 @@ namespace ffcpp {
|
|||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
int fps = _vStream->fps();
|
float fps = _vStream->fps();
|
||||||
FramePtr frame;
|
FramePtr frame;
|
||||||
if(_videoFrames.try_dequeue(frame)) {
|
if(_videoFrames.try_dequeue(frame)) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
AVFrame* f = frame->nativePtr();
|
AVFrame* f = frame->nativePtr();
|
||||||
_vSink->drawPlanarYUVFrame(f->data[0], f->data[1], f->data[2],
|
_vSink->drawPlanarYUVFrame(f->data[0], f->data[1], f->data[2],
|
||||||
f->linesize[0], f->linesize[1], f->linesize[2]);
|
f->linesize[0], f->linesize[1], f->linesize[2]);
|
||||||
|
++frameCounter;
|
||||||
|
if(frameCounter == 2398) {
|
||||||
|
auto end = std::chrono::system_clock::now();
|
||||||
|
std::chrono::duration<double> elapsed_seconds = end-start;
|
||||||
|
std::cout << "Elapsed time: " << elapsed_seconds.count() << std::endl;
|
||||||
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
} else {
|
} else {
|
||||||
std::cout << "=============== skip video frame" << std::endl;
|
std::cout << "=============== skip video frame" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000/fps));
|
std::this_thread::sleep_for(std::chrono::microseconds (static_cast<int64_t>(1000000/fps)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,16 +194,20 @@ namespace ffcpp {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint64_t curTime = std::chrono::system_clock::now().time_since_epoch().count();
|
// TODO: Implement correct behaviour for planar audio
|
||||||
// std::cout << "fill samples buffer: " << length << ", " << (curTime - time) << std::endl;
|
|
||||||
// time = curTime;
|
|
||||||
|
|
||||||
AVFrame* f = frame->nativePtr();
|
AVFrame* f = frame->nativePtr();
|
||||||
int frameSize = frame->size();
|
int frameSize = frame->size();
|
||||||
|
|
||||||
|
// std::cout << "Samples: " << f->nb_samples << std::endl;
|
||||||
|
// std::cout << "Channels: " << f->channels << std::endl;
|
||||||
|
// std::cout << "Bytes per sample: " << av_get_bytes_per_sample(_aStream->codec()->sampleFormat()) << std::endl;
|
||||||
|
// std::cout << "Linesize[0]: " << f->linesize[0] << std::endl;
|
||||||
|
// std::cout << "Linesize[1]: " << f->linesize[1] << std::endl;
|
||||||
|
// std::cout << "Frame size: " << frameSize << std::endl;
|
||||||
|
|
||||||
if(copied + frameSize > length) {
|
if(copied + frameSize > length) {
|
||||||
memcpy(data + copied, f->data[0], length - copied);
|
memcpy(data + copied, f->data[0], length - copied);
|
||||||
memcpy(_aSamplesBuffer.get(), f->data + length - copied, frameSize - length + copied);
|
memcpy(_aSamplesBuffer.get(), f->data[0] + length - copied, frameSize - length + copied);
|
||||||
_samplesInBuffer = frameSize - length + copied;
|
_samplesInBuffer = frameSize - length + copied;
|
||||||
copied = length;
|
copied = length;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -7,7 +7,7 @@ namespace ffcpp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream(AVStream *stream): _stream(stream) {
|
Stream::Stream(AVStream *stream): _stream(stream) {
|
||||||
_codec = std::make_shared<Codec>(_stream->codecpar->codec_id, CodecType::Decoder);
|
_codec = std::make_shared<Codec>(_stream->codecpar->codec_id, CodecType::Decoder, _stream->codecpar);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream(AVStream *stream, CodecPtr codec): _stream(stream), _codec(codec) {
|
Stream::Stream(AVStream *stream, CodecPtr codec): _stream(stream), _codec(codec) {
|
||||||
@ -29,8 +29,8 @@ namespace ffcpp {
|
|||||||
_stream->time_base = timeBase;
|
_stream->time_base = timeBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Stream::fps() const {
|
float Stream::fps() const {
|
||||||
return _stream->avg_frame_rate.num/_stream->avg_frame_rate.den;
|
return 1.0*_stream->avg_frame_rate.num/_stream->avg_frame_rate.den;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream(Stream&& stream) noexcept {
|
Stream::Stream(Stream&& stream) noexcept {
|
||||||
|
|||||||
@ -8,7 +8,6 @@ extern "C" {
|
|||||||
namespace ffcpp {
|
namespace ffcpp {
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
av_register_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void throwIfError(int result, const std::string& description) {
|
void throwIfError(int result, const std::string& description) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user