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) { ...@@ -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) JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_captureVideoFrame(JNIEnv *jenv, jclass jcls, jobject image, jint rotation)
{ {
jclass imageClass = jenv->GetObjectClass(image); jclass imageClass = jenv->GetObjectClass(image);
...@@ -348,6 +370,7 @@ JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_unregisterVideoCallbac ...@@ -348,6 +370,7 @@ JNIEXPORT void JNICALL Java_cx_ring_daemon_RingserviceJNI_unregisterVideoCallbac
%native(unregisterVideoCallback) void unregisterVideoCallback(jstring, jlong); %native(unregisterVideoCallback) void unregisterVideoCallback(jstring, jlong);
%native(captureVideoFrame) void captureVideoFrame(jobject, jint); %native(captureVideoFrame) void captureVideoFrame(jobject, jint);
%native(captureVideoPacket) void captureVideoPacket(jobject, jint, jint, jboolean, jlong);
namespace DRing { namespace DRing {
......
...@@ -49,7 +49,13 @@ ...@@ -49,7 +49,13 @@
namespace DRing { namespace DRing {
MediaFrame::MediaFrame() 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_) if (not frame_)
throw std::bad_alloc(); throw std::bad_alloc();
...@@ -66,6 +72,13 @@ void ...@@ -66,6 +72,13 @@ void
MediaFrame::reset() noexcept MediaFrame::reset() noexcept
{ {
av_frame_unref(frame_.get()); 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) AudioFrame::AudioFrame(const ring::AudioFormat& format, size_t nb_samples)
......
...@@ -82,15 +82,18 @@ public: ...@@ -82,15 +82,18 @@ public:
// Return a pointer on underlaying buffer // Return a pointer on underlaying buffer
const AVFrame* pointer() const noexcept { return frame_.get(); } const AVFrame* pointer() const noexcept { return frame_.get(); }
AVFrame* pointer() noexcept { return frame_.get(); } AVFrame* pointer() noexcept { return frame_.get(); }
AVPacket* packet() const noexcept { return packet_.get(); }
// Fill this MediaFrame with data from o // Fill this MediaFrame with data from o
void copyFrom(const MediaFrame& o); void copyFrom(const MediaFrame& o);
void setPacket(std::unique_ptr<AVPacket, void(*)(AVPacket*)>&& pkt);
// Reset internal buffers (return to an empty MediaFrame) // Reset internal buffers (return to an empty MediaFrame)
virtual void reset() noexcept; virtual void reset() noexcept;
protected: protected:
std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame_; std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame_;
std::unique_ptr<AVPacket, void(*)(AVPacket*)> packet_;
}; };
class DRING_PUBLIC AudioFrame : public MediaFrame { class DRING_PUBLIC AudioFrame : public MediaFrame {
......
...@@ -419,19 +419,7 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx) ...@@ -419,19 +419,7 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx)
} }
if (pkt.size) { if (pkt.size) {
pkt.stream_index = streamIdx; if (send(pkt))
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
break; break;
} }
} }
...@@ -440,6 +428,25 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx) ...@@ -440,6 +428,25 @@ MediaEncoder::encode(AVFrame* frame, int streamIdx)
return 0; 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 int
MediaEncoder::flush() MediaEncoder::flush()
{ {
......
...@@ -73,6 +73,8 @@ public: ...@@ -73,6 +73,8 @@ public:
void startIO(); void startIO();
void setIOContext(const std::unique_ptr<MediaIOHandle> &ioctx); void setIOContext(const std::unique_ptr<MediaIOHandle> &ioctx);
bool send(AVPacket& packet);
#ifdef RING_VIDEO #ifdef RING_VIDEO
int encode(VideoFrame &input, bool is_keyframe, int64_t frame_number); int encode(VideoFrame &input, bool is_keyframe, int64_t frame_number);
#endif // RING_VIDEO #endif // RING_VIDEO
......
...@@ -67,14 +67,18 @@ VideoSender::~VideoSender() ...@@ -67,14 +67,18 @@ VideoSender::~VideoSender()
void void
VideoSender::encodeAndSendVideo(VideoFrame& input_frame) VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
{ {
bool is_keyframe = forceKeyFrame_ > 0 if (auto packet = input_frame.packet()) {
or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0); videoEncoder_->send(*packet);
} else {
if (is_keyframe) bool is_keyframe = forceKeyFrame_ > 0
--forceKeyFrame_; or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0) if (is_keyframe)
RING_ERR("encoding failed"); --forceKeyFrame_;
if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
RING_ERR("encoding failed");
}
} }
void 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