2022-05-26 11:00:48 +08:00
|
|
|
|
/*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
|
2022-05-25 15:38:32 +08:00
|
|
|
|
*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
|
2022-05-25 15:38:32 +08:00
|
|
|
|
*
|
2023-12-09 16:23:51 +08:00
|
|
|
|
* Use of this source code is governed by MIT-like license that can be found in the
|
2022-05-25 15:38:32 +08:00
|
|
|
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|
|
|
|
* may be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "mk_frame.h"
|
2023-07-06 14:11:21 +08:00
|
|
|
|
#include "Record/MPEG.h"
|
2023-12-09 16:23:51 +08:00
|
|
|
|
#include "Extension/Factory.h"
|
2022-05-25 15:38:32 +08:00
|
|
|
|
|
|
|
|
|
using namespace mediakit;
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
2023-12-09 16:23:51 +08:00
|
|
|
|
#define XX(name, type, value, str, mpeg_id, mp4_id) API_EXPORT const int MK##name = value;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
CODEC_MAP(XX)
|
|
|
|
|
#undef XX
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-09 16:23:51 +08:00
|
|
|
|
namespace {
|
|
|
|
|
class BufferFromPtr : public toolkit::Buffer {
|
2022-05-25 15:38:32 +08:00
|
|
|
|
public:
|
2023-12-09 16:23:51 +08:00
|
|
|
|
BufferFromPtr(char *ptr, size_t size, on_mk_frame_data_release cb, std::shared_ptr<void> user_data) {
|
|
|
|
|
_ptr = ptr;
|
|
|
|
|
_size = size;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
_cb = cb;
|
2023-02-11 15:14:18 +08:00
|
|
|
|
_user_data = std::move(user_data);
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-09 16:23:51 +08:00
|
|
|
|
~BufferFromPtr() override {
|
|
|
|
|
_cb(_user_data.get(), _ptr);
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-09 16:23:51 +08:00
|
|
|
|
char *data() const override { return _ptr; }
|
|
|
|
|
size_t size() const override { return _size; }
|
2022-05-25 15:38:32 +08:00
|
|
|
|
|
|
|
|
|
private:
|
2023-12-09 16:23:51 +08:00
|
|
|
|
char *_ptr;
|
|
|
|
|
size_t _size;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
on_mk_frame_data_release _cb;
|
2023-02-11 15:14:18 +08:00
|
|
|
|
std::shared_ptr<void> _user_data;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
};
|
2023-12-09 16:23:51 +08:00
|
|
|
|
}; // namespace
|
2022-05-25 15:38:32 +08:00
|
|
|
|
|
2023-12-09 16:23:51 +08:00
|
|
|
|
static mk_frame mk_frame_create_complex(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
|
|
|
|
|
on_mk_frame_data_release cb, std::shared_ptr<void> user_data) {
|
|
|
|
|
if (!cb) {
|
|
|
|
|
// no cacheable
|
|
|
|
|
return (mk_frame) new Frame::Ptr(Factory::getFrameFromPtr((CodecId)codec_id, data, size, dts, pts));
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
2023-12-09 16:23:51 +08:00
|
|
|
|
// cacheable
|
|
|
|
|
auto buffer = std::make_shared<BufferFromPtr>((char *)data, size, cb, std::move(user_data));
|
|
|
|
|
return (mk_frame) new Frame::Ptr(Factory::getFrameFromBuffer((CodecId)codec_id, std::move(buffer), dts, pts));
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-08 17:13:39 +08:00
|
|
|
|
API_EXPORT mk_frame API_CALL mk_frame_create(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
|
2023-12-09 16:23:51 +08:00
|
|
|
|
on_mk_frame_data_release cb, void *user_data) {
|
2023-02-11 15:14:18 +08:00
|
|
|
|
return mk_frame_create2(codec_id, dts, pts, data, size, cb, user_data, nullptr);
|
|
|
|
|
}
|
2023-12-09 16:23:51 +08:00
|
|
|
|
|
2023-02-11 15:14:18 +08:00
|
|
|
|
API_EXPORT mk_frame API_CALL mk_frame_create2(int codec_id, uint64_t dts, uint64_t pts, const char *data, size_t size,
|
2023-12-09 16:23:51 +08:00
|
|
|
|
on_mk_frame_data_release cb, void *user_data, on_user_data_free user_data_free) {
|
2023-02-11 15:14:18 +08:00
|
|
|
|
std::shared_ptr<void> ptr(user_data, user_data_free ? user_data_free : [](void *) {});
|
2023-12-09 16:23:51 +08:00
|
|
|
|
return mk_frame_create_complex(codec_id, dts, pts, data, size, cb, std::move(ptr));
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_frame_unref(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
delete (Frame::Ptr *) frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT mk_frame API_CALL mk_frame_ref(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
2023-02-26 21:45:14 +08:00
|
|
|
|
return (mk_frame)new Frame::Ptr(Frame::getCacheAbleFrame(*((Frame::Ptr *) frame)));
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT int API_CALL mk_frame_codec_id(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->getCodecId();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT const char *API_CALL mk_frame_codec_name(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->getCodecName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT int API_CALL mk_frame_is_video(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->getTrackType() == TrackVideo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT const char *API_CALL mk_frame_get_data(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->data();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT size_t API_CALL mk_frame_get_data_size(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT size_t API_CALL mk_frame_get_data_prefix_size(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->prefixSize();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-08 17:13:39 +08:00
|
|
|
|
API_EXPORT uint64_t API_CALL mk_frame_get_dts(mk_frame frame) {
|
2022-05-25 15:38:32 +08:00
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->dts();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-08 17:13:39 +08:00
|
|
|
|
API_EXPORT uint64_t API_CALL mk_frame_get_pts(mk_frame frame) {
|
2022-05-25 15:38:32 +08:00
|
|
|
|
assert(frame);
|
|
|
|
|
return (*((Frame::Ptr *) frame))->pts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT uint32_t API_CALL mk_frame_get_flags(mk_frame frame) {
|
|
|
|
|
assert(frame);
|
|
|
|
|
auto &ref = *((Frame::Ptr *) frame);
|
|
|
|
|
uint32_t ret = 0;
|
|
|
|
|
if (ref->keyFrame()) {
|
2022-09-09 11:05:42 +08:00
|
|
|
|
ret |= MK_FRAME_FLAG_IS_KEY;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
if (ref->configFrame()) {
|
2022-09-09 11:05:42 +08:00
|
|
|
|
ret |= MK_FRAME_FLAG_IS_CONFIG;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
if (ref->dropAble()) {
|
2022-09-09 11:05:42 +08:00
|
|
|
|
ret |= MK_FRAME_FLAG_DROP_ABLE;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
if (!ref->decodeAble()) {
|
2022-09-09 11:05:42 +08:00
|
|
|
|
ret |= MK_FRAME_FLAG_NOT_DECODE_ABLE;
|
2022-05-25 15:38:32 +08:00
|
|
|
|
}
|
|
|
|
|
return ret;
|
2022-09-09 11:05:42 +08:00
|
|
|
|
}
|
2023-07-02 12:25:30 +08:00
|
|
|
|
|
|
|
|
|
API_EXPORT mk_frame_merger API_CALL mk_frame_merger_create(int type) {
|
|
|
|
|
return reinterpret_cast<mk_frame_merger>(new FrameMerger(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_frame_merger_release(mk_frame_merger ctx) {
|
|
|
|
|
assert(ctx);
|
|
|
|
|
delete reinterpret_cast<FrameMerger *>(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_frame_merger_clear(mk_frame_merger ctx) {
|
|
|
|
|
assert(ctx);
|
|
|
|
|
reinterpret_cast<FrameMerger *>(ctx)->clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_frame_merger_flush(mk_frame_merger ctx) {
|
|
|
|
|
assert(ctx);
|
|
|
|
|
reinterpret_cast<FrameMerger *>(ctx)->flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_frame_merger_input(mk_frame_merger ctx, mk_frame frame, on_mk_frame_merger cb, void *user_data) {
|
|
|
|
|
assert(ctx && frame && cb);
|
|
|
|
|
reinterpret_cast<FrameMerger *>(ctx)->inputFrame(*((Frame::Ptr *) frame), [cb, user_data](uint64_t dts, uint64_t pts, const toolkit::Buffer::Ptr &buffer, bool have_key_frame) {
|
|
|
|
|
cb(user_data, dts, pts, (mk_buffer)(&buffer), have_key_frame);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-07-06 14:11:21 +08:00
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class MpegMuxerForC : public MpegMuxer {
|
|
|
|
|
public:
|
|
|
|
|
using onMuxer = std::function<void(const char *frame, size_t size, uint64_t timestamp, int key_pos)>;
|
|
|
|
|
MpegMuxerForC(bool is_ps) : MpegMuxer(is_ps) {
|
|
|
|
|
_cb = nullptr;
|
|
|
|
|
}
|
|
|
|
|
~MpegMuxerForC() { MpegMuxer::flush(); };
|
|
|
|
|
|
|
|
|
|
void setOnMuxer(onMuxer cb) {
|
|
|
|
|
_cb = std::move(cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void onWrite(std::shared_ptr<toolkit::Buffer> buffer, uint64_t timestamp, bool key_pos) override {
|
|
|
|
|
if (_cb) {
|
|
|
|
|
if (!buffer) {
|
|
|
|
|
_cb(nullptr, 0, timestamp, key_pos);
|
|
|
|
|
} else {
|
|
|
|
|
_cb(buffer->data(), buffer->size(), timestamp, key_pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
onMuxer _cb;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
API_EXPORT mk_mpeg_muxer API_CALL mk_mpeg_muxer_create(on_mk_mpeg_muxer_frame cb, void *user_data, int is_ps){
|
|
|
|
|
assert(cb);
|
|
|
|
|
auto ret = new MpegMuxerForC(is_ps);
|
|
|
|
|
std::shared_ptr<void> ptr(user_data, [](void *) {});
|
|
|
|
|
ret->setOnMuxer([cb, ptr, ret](const char *frame, size_t size, uint64_t timestamp, int key_pos) {
|
|
|
|
|
cb(ptr.get(), reinterpret_cast<mk_mpeg_muxer>(ret), frame, size, timestamp, key_pos);
|
|
|
|
|
});
|
|
|
|
|
return reinterpret_cast<mk_mpeg_muxer>(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_mpeg_muxer_release(mk_mpeg_muxer ctx){
|
|
|
|
|
assert(ctx);
|
|
|
|
|
auto ptr = reinterpret_cast<MpegMuxerForC *>(ctx);
|
|
|
|
|
delete ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_mpeg_muxer_init_track(mk_mpeg_muxer ctx, void* track) {
|
|
|
|
|
assert(ctx && track);
|
|
|
|
|
auto ptr = reinterpret_cast<MpegMuxerForC *>(ctx);
|
|
|
|
|
ptr->addTrack(*((Track::Ptr *) track));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT void API_CALL mk_mpeg_muxer_init_complete(mk_mpeg_muxer ctx) {
|
|
|
|
|
assert(ctx);
|
|
|
|
|
auto ptr = reinterpret_cast<MpegMuxerForC *>(ctx);
|
|
|
|
|
ptr->addTrackCompleted();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
API_EXPORT int API_CALL mk_mpeg_muxer_input_frame(mk_mpeg_muxer ctx, mk_frame frame){
|
|
|
|
|
assert(ctx && frame);
|
|
|
|
|
auto ptr = reinterpret_cast<MpegMuxerForC *>(ctx);
|
|
|
|
|
return ptr->inputFrame(*((Frame::Ptr *) frame));
|
|
|
|
|
}
|