Commit 2aad6913 authored by Adrien Béraud's avatar Adrien Béraud

video: allow capturing encoded packets

Change-Id: Idb983898ae2cd0d9b58a46baf76073b9eac4e3be
parent aff0eda4
......@@ -129,6 +129,28 @@ int AndroidFormatToAVFormat(int androidformat) {
}
}
JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_captureVideoPacket(JNIEnv *jenv, jclass jcls, jobject buffer, jint size, jint offset, jboolean keyframe, jlong timestamp)
{
auto frame = DRing::getNewFrame();
if (not frame)
return;
auto packet = std::unique_ptr<AVPacket, void(*)(AVPacket*)>(new AVPacket, [](AVPacket* pkt){
if (pkt) {
av_packet_unref(pkt);
delete pkt;
}
});
av_init_packet(packet.get());
if (keyframe)
packet->flags = AV_PKT_FLAG_KEY;
auto data = (uint8_t*)jenv->GetDirectBufferAddress(buffer);
packet->data = data + offset;
packet->size = size;
packet->pts = timestamp;
frame->setPacket(std::move(packet));
DRing::publishFrame();
}
JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_captureVideoFrame(JNIEnv *jenv, jclass jcls, jobject image, jint rotation)
{
jclass imageClass = jenv->GetObjectClass(image);
......@@ -348,6 +370,7 @@ JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_unregisterVideoCallbac
%native(unregisterVideoCallback) void unregisterVideoCallback(jstring, jlong);
%native(captureVideoFrame) void captureVideoFrame(jobject, jint);
%native(captureVideoPacket) void captureVideoPacket(jobject, jint, jint, jboolean, jlong);
namespace DRing {
......
......@@ -49,7 +49,13 @@
namespace DRing {
MediaFrame::MediaFrame()
: frame_ {av_frame_alloc(), [](AVFrame* frame){ av_frame_free(&frame); }}
: frame_ {av_frame_alloc(), [](AVFrame* frame){ av_frame_free(&frame); }},
packet_(nullptr, [](AVPacket* p) {
if (p) {
av_packet_unref(p);
delete p;
}
})
{
if (not frame_)
throw std::bad_alloc();
......@@ -66,6 +72,13 @@ void
MediaFrame::reset() noexcept
{
av_frame_unref(frame_.get());
packet_.reset();
}
void
MediaFrame::setPacket(std::unique_ptr<AVPacket, void(*)(AVPacket*)>&& pkt)
{
packet_ = std::move(pkt);
}
AudioFrame::AudioFrame(const ring::AudioFormat& format, size_t nb_samples)
......
......@@ -82,15 +82,18 @@ public:
// Return a pointer on underlaying buffer
const AVFrame* pointer() const noexcept { return frame_.get(); }
AVFrame* pointer() noexcept { return frame_.get(); }
AVPacket* packet() const noexcept { return packet_.get(); }
// Fill this MediaFrame with data from o
void copyFrom(const MediaFrame& o);
void setPacket(std::unique_ptr<AVPacket, void(*)(AVPacket*)>&& pkt);
// Reset internal buffers (return to an empty MediaFrame)
virtual void reset() noexcept;
protected:
std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame_;
std::unique_ptr<AVPacket, void(*)(AVPacket*)> packet_;
};
class DRING_PUBLIC AudioFrame : public MediaFrame {
......
......@@ -419,19 +419,7 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx)
}
if (pkt.size) {
pkt.stream_index = streamIdx;
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, encoderCtx->time_base,
outputCtx_->streams[streamIdx]->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, encoderCtx->time_base,
outputCtx_->streams[streamIdx]->time_base);
// write the compressed frame
ret = av_write_frame(outputCtx_, &pkt);
if (ret < 0) {
RING_ERR() << "av_write_frame failed: " << libav_utils::getError(ret);
} else
if (send(pkt))
break;
}
}
......@@ -440,6 +428,25 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx)
return 0;
}
bool
MediaEncoder::send(AVPacket& pkt)
{
auto streamIdx = currentStreamIdx_;
pkt.stream_index = streamIdx;
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, AVRational{1, 20},
outputCtx_->streams[streamIdx]->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, AVRational{1, 20},
outputCtx_->streams[streamIdx]->time_base);
// write the compressed frame
auto ret = av_write_frame(outputCtx_, &pkt);
if (ret < 0) {
RING_ERR() << "av_write_frame failed: " << libav_utils::getError(ret);
}
return ret >= 0;
}
int
MediaEncoder::flush()
{
......
......@@ -73,6 +73,8 @@ public:
void startIO();
void setIOContext(const std::unique_ptr<MediaIOHandle> &ioctx);
bool send(AVPacket& packet);
#ifdef RING_VIDEO
int encode(VideoFrame &input, bool is_keyframe, int64_t frame_number);
#endif // RING_VIDEO
......
......@@ -67,14 +67,18 @@ VideoSender::~VideoSender()
void
VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
{
bool is_keyframe = forceKeyFrame_ > 0
or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
if (is_keyframe)
--forceKeyFrame_;
if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
RING_ERR("encoding failed");
if (auto packet = input_frame.packet()) {
videoEncoder_->send(*packet);
} else {
bool is_keyframe = forceKeyFrame_ > 0
or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
if (is_keyframe)
--forceKeyFrame_;
if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
RING_ERR("encoding failed");
}
}
void
......
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