Mux mp4 without video decoder and encoder.
This commit is contained in:
parent
c434f4fbe4
commit
03993fde2e
Binary file not shown.
|
@ -146,20 +146,13 @@ void inline FfmpegDecoder::AVParseData(const void *data, const size_t &size,
|
|||
}
|
||||
uint8_t *frameData = (uint8_t *)data;
|
||||
size_t data_size = size;
|
||||
size_t parse_size = 0;
|
||||
while (data_size > 0) {
|
||||
if (data_size > 4096) {
|
||||
parse_size = 4096;
|
||||
}
|
||||
else {
|
||||
parse_size = data_size;
|
||||
}
|
||||
int ret = av_parser_parse2(mParser,
|
||||
mCodecCtx,
|
||||
&mPacket->data,
|
||||
&mPacket->size,
|
||||
frameData,
|
||||
parse_size,
|
||||
data_size,
|
||||
AV_NOPTS_VALUE,
|
||||
AV_NOPTS_VALUE,
|
||||
0);
|
||||
|
|
|
@ -34,7 +34,7 @@ extern "C" {
|
|||
#include <memory>
|
||||
// #include <mutex>
|
||||
#include <string>
|
||||
FfmpegMuxStreamV2::FfmpegMuxStreamV2() : mOutputFormat(nullptr), mOptions(nullptr)
|
||||
FfmpegMuxStreamV2::FfmpegMuxStreamV2() : mOutputFormat(nullptr), mOptions(nullptr), mFilesMuxing(false)
|
||||
{
|
||||
}
|
||||
StatusCode FfmpegMuxStreamV2::OpenOutputFile(const std::string &fileName)
|
||||
|
@ -43,7 +43,7 @@ StatusCode FfmpegMuxStreamV2::OpenOutputFile(const std::string &fileName)
|
|||
}
|
||||
StatusCode FfmpegMuxStreamV2::CloseOutputFile(void)
|
||||
{
|
||||
if (mOutputFormat && mOutputFormat->pb) {
|
||||
if (mOutputFormat && mOutputFormat->pb && mFilesMuxing) {
|
||||
av_write_trailer(mOutputFormat);
|
||||
}
|
||||
if (mVideoStream) {
|
||||
|
@ -64,6 +64,38 @@ StatusCode FfmpegMuxStreamV2::CloseOutputFile(void)
|
|||
}
|
||||
void FfmpegMuxStreamV2::GetStreamData(const void *data, const size_t &size, const StreamInfo &streamInfo)
|
||||
{
|
||||
int ret = 0;
|
||||
if (!mFilesMuxing) {
|
||||
bool fileMuxing = false;
|
||||
fileMuxing = mVideoStream->CheckStreamHeader(data, size);
|
||||
if (fileMuxing) {
|
||||
av_dump_format(mOutputFormat, 0, "./test.mp4", 1);
|
||||
/* open the output file, if needed */
|
||||
if (!(mOutputFormat->oformat->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&mOutputFormat->pb, "./test.mp4", AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
char error_str[AV_ERROR_MAX_STRING_SIZE] = {0};
|
||||
LogError("Could not open '%s': %s\n",
|
||||
"./test.mp4",
|
||||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
}
|
||||
}
|
||||
/* Write the stream header, if any. */
|
||||
ret = avformat_write_header(mOutputFormat, nullptr);
|
||||
if (ret < 0) {
|
||||
char error_str[AV_ERROR_MAX_STRING_SIZE] = {0};
|
||||
LogError("Error occurred when opening output file: %s\n",
|
||||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
return;
|
||||
}
|
||||
mFilesMuxing = true;
|
||||
}
|
||||
else {
|
||||
LogWarning("Stream header not found, skip this frame.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogInfo("Write frame size: %zu.\n", size);
|
||||
if (streamInfo.mType == STREAM_TYPE_VIDEO_H264 && mVideoStream) {
|
||||
mVideoStream->WriteSourceData(data, size);
|
||||
}
|
||||
|
@ -71,7 +103,7 @@ void FfmpegMuxStreamV2::GetStreamData(const void *data, const size_t &size, cons
|
|||
mAudioStream->WriteSourceData(data, size);
|
||||
}
|
||||
}
|
||||
StatusCode FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
||||
StatusCode inline FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
||||
{
|
||||
AVDictionary *opt = nullptr;
|
||||
int ret = 0;
|
||||
|
@ -84,7 +116,8 @@ StatusCode FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
|||
/* Add the audio and video streams using the default format codecs
|
||||
* and initialize the codecs. */
|
||||
if (mOutputFormat->oformat->video_codec != AV_CODEC_ID_NONE) {
|
||||
mVideoStream = AddStream(mOutputFormat, mOutputFormat->oformat->video_codec, AV_CODEC_ID_H264);
|
||||
mVideoStream = AddStream(mOutputFormat, AV_CODEC_ID_NONE, AV_CODEC_ID_NONE);
|
||||
// mVideoStream = AddStream(mOutputFormat, mOutputFormat->oformat->video_codec, AV_CODEC_ID_H264);
|
||||
mVideoStream->SetWriteSourceDataCallback(
|
||||
std::bind(&FfmpegMuxStreamV2::GetAVPacketDataCallback, this, std::placeholders::_1));
|
||||
}
|
||||
|
@ -93,6 +126,7 @@ StatusCode FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
|||
mAudioStream->SetWriteSourceDataCallback(
|
||||
std::bind(&FfmpegMuxStreamV2::GetAVPacketDataCallback, this, std::placeholders::_1));
|
||||
}
|
||||
return CreateStatusCode(STATUS_CODE_OK);
|
||||
av_dump_format(mOutputFormat, 0, fileName.c_str(), 1);
|
||||
/* open the output file, if needed */
|
||||
if (!(mOutputFormat->oformat->flags & AVFMT_NOFILE)) {
|
||||
|
@ -112,6 +146,7 @@ StatusCode FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
|||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
||||
}
|
||||
mFilesMuxing = true;
|
||||
return CreateStatusCode(STATUS_CODE_OK);
|
||||
}
|
||||
void FfmpegMuxStreamV2::GetAVPacketDataCallback(AVPacket *pkt)
|
||||
|
|
137
utils/MediaBase/src/FfmpegMuxStreamV2.cpp_bak
Normal file
137
utils/MediaBase/src/FfmpegMuxStreamV2.cpp_bak
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Fancy Code.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "FfmpegMuxStreamV2.h"
|
||||
#include "FfmpegOutputStream.h"
|
||||
#include "ILog.h"
|
||||
#include "MediaBase.h"
|
||||
#include "StatusCode.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <libavcodec/codec_id.h>
|
||||
#include <libavcodec/packet.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavformat/avio.h>
|
||||
#include <libavutil/dict.h>
|
||||
#include <libavutil/error.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
// #include <mutex>
|
||||
#include <string>
|
||||
FfmpegMuxStreamV2::FfmpegMuxStreamV2() : mOutputFormat(nullptr), mOptions(nullptr)
|
||||
{
|
||||
}
|
||||
StatusCode FfmpegMuxStreamV2::OpenOutputFile(const std::string &fileName)
|
||||
{
|
||||
return OpenMuxOutputFile(fileName);
|
||||
}
|
||||
StatusCode FfmpegMuxStreamV2::CloseOutputFile(void)
|
||||
{
|
||||
if (mOutputFormat && mOutputFormat->pb) {
|
||||
av_write_trailer(mOutputFormat);
|
||||
}
|
||||
if (mVideoStream) {
|
||||
mVideoStream->UnInit();
|
||||
}
|
||||
if (mAudioStream) {
|
||||
mAudioStream->UnInit();
|
||||
}
|
||||
if (nullptr == mOutputFormat) {
|
||||
return CreateStatusCode(STATUS_CODE_OK);
|
||||
}
|
||||
if (!(mOutputFormat->oformat->flags & AVFMT_NOFILE)) {
|
||||
/* Close the output file. */
|
||||
avio_closep(&mOutputFormat->pb);
|
||||
}
|
||||
avformat_free_context(mOutputFormat);
|
||||
return CreateStatusCode(STATUS_CODE_OK);
|
||||
}
|
||||
void FfmpegMuxStreamV2::GetStreamData(const void *data, const size_t &size, const StreamInfo &streamInfo)
|
||||
{
|
||||
if (streamInfo.mType == STREAM_TYPE_VIDEO_H264 && mVideoStream) {
|
||||
mVideoStream->WriteSourceData(data, size);
|
||||
}
|
||||
if (streamInfo.mType == STREAM_TYPE_AUDIO_G711A && mAudioStream) {
|
||||
mAudioStream->WriteSourceData(data, size);
|
||||
}
|
||||
}
|
||||
StatusCode inline FfmpegMuxStreamV2::OpenMuxOutputFile(const std::string &fileName)
|
||||
{
|
||||
AVDictionary *opt = nullptr;
|
||||
int ret = 0;
|
||||
/* allocate the output media context */
|
||||
avformat_alloc_output_context2(&mOutputFormat, nullptr, "mp4", fileName.c_str());
|
||||
if (!mOutputFormat) {
|
||||
LogError("Could not deduce output format from file.\n");
|
||||
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
||||
}
|
||||
/* Add the audio and video streams using the default format codecs
|
||||
* and initialize the codecs. */
|
||||
if (mOutputFormat->oformat->video_codec != AV_CODEC_ID_NONE) {
|
||||
mVideoStream = AddStream(mOutputFormat, mOutputFormat->oformat->video_codec, AV_CODEC_ID_H264);
|
||||
mVideoStream->SetWriteSourceDataCallback(
|
||||
std::bind(&FfmpegMuxStreamV2::GetAVPacketDataCallback, this, std::placeholders::_1));
|
||||
}
|
||||
if (mOutputFormat->oformat->audio_codec != AV_CODEC_ID_NONE) {
|
||||
mAudioStream = AddStream(mOutputFormat, mOutputFormat->oformat->audio_codec, AV_CODEC_ID_PCM_ALAW);
|
||||
mAudioStream->SetWriteSourceDataCallback(
|
||||
std::bind(&FfmpegMuxStreamV2::GetAVPacketDataCallback, this, std::placeholders::_1));
|
||||
}
|
||||
av_dump_format(mOutputFormat, 0, fileName.c_str(), 1);
|
||||
/* open the output file, if needed */
|
||||
if (!(mOutputFormat->oformat->flags & AVFMT_NOFILE)) {
|
||||
ret = avio_open(&mOutputFormat->pb, fileName.c_str(), AVIO_FLAG_WRITE);
|
||||
if (ret < 0) {
|
||||
char error_str[AV_ERROR_MAX_STRING_SIZE] = {0};
|
||||
LogError("Could not open '%s': %s\n",
|
||||
fileName.c_str(),
|
||||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
}
|
||||
}
|
||||
/* Write the stream header, if any. */
|
||||
ret = avformat_write_header(mOutputFormat, &opt);
|
||||
if (ret < 0) {
|
||||
char error_str[AV_ERROR_MAX_STRING_SIZE] = {0};
|
||||
LogError("Error occurred when opening output file: %s\n",
|
||||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
return CreateStatusCode(STATUS_CODE_NOT_OK);
|
||||
}
|
||||
return CreateStatusCode(STATUS_CODE_OK);
|
||||
}
|
||||
void FfmpegMuxStreamV2::GetAVPacketDataCallback(AVPacket *pkt)
|
||||
{
|
||||
// std::lock_guard<std::mutex> locker(mMutex);
|
||||
int ret = 0;
|
||||
ret = av_interleaved_write_frame(mOutputFormat, pkt);
|
||||
/* pkt is now blank (av_interleaved_write_frame() takes ownership of
|
||||
* its contents and resets pkt), so that no unreferencing is necessary.
|
||||
* This would be different if one used av_write_frame(). */
|
||||
if (ret < 0) {
|
||||
char error_str[AV_ERROR_MAX_STRING_SIZE] = {0};
|
||||
LogInfo("Error while writing output packet: %s\n",
|
||||
av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret));
|
||||
}
|
||||
}
|
||||
std::shared_ptr<FfmpegOutputStream> FfmpegMuxStreamV2::AddStream(AVFormatContext *outputFormat,
|
||||
enum AVCodecID encodecId, enum AVCodecID decodecId)
|
||||
{
|
||||
auto stream = std::make_shared<FfmpegOutputStream>(encodecId, decodecId);
|
||||
stream->Init(outputFormat);
|
||||
return stream;
|
||||
}
|
|
@ -63,5 +63,6 @@ private:
|
|||
std::shared_ptr<FfmpegOutputStream> mVideoStream;
|
||||
std::shared_ptr<FfmpegOutputStream> mAudioStream;
|
||||
AVDictionary *mOptions;
|
||||
bool mFilesMuxing;
|
||||
};
|
||||
#endif
|
|
@ -30,7 +30,7 @@ extern "C" {
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
FfmpegOutputStream::FfmpegOutputStream(const AVCodecID &encodecId, const AVCodecID &dncodecId)
|
||||
: mEncodecId(encodecId), mDeccodecId(dncodecId), mTmpPkt(nullptr), mStream(nullptr)
|
||||
: mEncodecId(encodecId), mDeccodecId(dncodecId), mTmpPkt(nullptr), mStream(nullptr), mStreamHeaderWritten(false)
|
||||
{
|
||||
}
|
||||
bool FfmpegOutputStream::Init(AVFormatContext *outputFormat)
|
||||
|
@ -46,33 +46,107 @@ bool FfmpegOutputStream::Init(AVFormatContext *outputFormat)
|
|||
LogError("Could not allocate stream\n");
|
||||
return false;
|
||||
}
|
||||
mDecoder = std::make_shared<FfmpegDecoder>(mDeccodecId);
|
||||
mDecoder->Init();
|
||||
if (mDeccodecId != AV_CODEC_ID_NONE) {
|
||||
mDecoder = std::make_shared<FfmpegDecoder>(mDeccodecId);
|
||||
mDecoder->Init();
|
||||
}
|
||||
mStream->id = outputFormat->nb_streams - 1;
|
||||
mEncoder = std::make_shared<FfmpegEncoder>(mEncodecId);
|
||||
mEncoder->Init(outputFormat->flags);
|
||||
mStream->time_base = mEncoder->GetTimeBase();
|
||||
mEncoder->OpenEncoder(nullptr, mStream);
|
||||
if (mEncodecId != AV_CODEC_ID_NONE) {
|
||||
mEncoder = std::make_shared<FfmpegEncoder>(mEncodecId);
|
||||
mEncoder->Init(outputFormat->flags);
|
||||
mStream->time_base = mEncoder->GetTimeBase();
|
||||
mEncoder->OpenEncoder(nullptr, mStream);
|
||||
}
|
||||
else {
|
||||
mStream->time_base = (AVRational){1, 15};
|
||||
// int ret = avcodec_parameters_copy(mStream->codecpar, in_codecpar);
|
||||
// if (ret < 0) {
|
||||
// LogError("Failed to copy codec parameters\n");
|
||||
// return false;
|
||||
// }
|
||||
mStream->codecpar->codec_id = AV_CODEC_ID_H264;
|
||||
mStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
mStream->codecpar->width = 1920;
|
||||
mStream->codecpar->height = 2160;
|
||||
// mStream->codecpar->bit_rate = 2073;
|
||||
mStream->codecpar->format = AV_PIX_FMT_YUV420P;
|
||||
mStream->codecpar->codec_tag = 0;
|
||||
mStream->codecpar->extradata = nullptr;
|
||||
mStream->codecpar->extradata_size = 0;
|
||||
// mEncoder = std::make_shared<FfmpegEncoder>(AV_CODEC_ID_MPEG4);
|
||||
// mEncoder->Init(outputFormat->flags);
|
||||
// mStream->time_base = mEncoder->GetTimeBase();
|
||||
// mEncoder->OpenEncoder(nullptr, mStream);
|
||||
// mEncoder->UnInit();
|
||||
// mEncoder.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void FfmpegOutputStream::UnInit(void)
|
||||
{
|
||||
mEncoder->UnInit();
|
||||
mDecoder->UnInit();
|
||||
if (mEncoder) {
|
||||
mEncoder->UnInit();
|
||||
mEncoder.reset();
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->UnInit();
|
||||
mDecoder.reset();
|
||||
}
|
||||
av_packet_free(&mTmpPkt);
|
||||
}
|
||||
void FfmpegOutputStream::WriteSourceData(const void *data, const size_t &size)
|
||||
{
|
||||
mDecoder->DecodeData(data, size, mDecodeCallback);
|
||||
if (mDecoder) {
|
||||
mDecoder->DecodeData(data, size, mDecodeCallback);
|
||||
return;
|
||||
}
|
||||
static unsigned long long u64Interval = 0;
|
||||
AVRational in_timebase = (AVRational){1, 15};
|
||||
if (mEncodeCallback) {
|
||||
mTmpPkt->data = (uint8_t *)data;
|
||||
mTmpPkt->size = size;
|
||||
mTmpPkt->stream_index = mStream->index;
|
||||
mTmpPkt->pts = u64Interval * 1000; // ת<><D7AA><EFBFBD><EFBFBD> us
|
||||
mTmpPkt->dts = mTmpPkt->pts;
|
||||
u64Interval += 70;
|
||||
/* copy packet */
|
||||
av_packet_rescale_ts(mTmpPkt, in_timebase, mStream->time_base);
|
||||
mTmpPkt->pos = -1;
|
||||
mEncodeCallback(mTmpPkt);
|
||||
}
|
||||
}
|
||||
void FfmpegOutputStream::SetWriteSourceDataCallback(std::function<void(AVPacket *pkt)> callback)
|
||||
{
|
||||
mEncodeCallback = callback;
|
||||
}
|
||||
bool FfmpegOutputStream::CheckStreamHeader(const void *data, const size_t &size)
|
||||
{
|
||||
if (mStreamHeaderWritten || mEncodecId != AV_CODEC_ID_NONE) {
|
||||
return true;
|
||||
}
|
||||
char *pData = (char *)data;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if ((0x00 == pData[i]) && (0x00 == pData[i + 1]) && (0x00 == pData[i + 2]) && (0x01 == pData[i + 3]) &&
|
||||
(0x5 == (pData[i + 4] & 0x1F))) {
|
||||
uint8_t *extradata = (uint8_t *)av_mallocz(i + 1);
|
||||
if (!extradata) {
|
||||
LogError("Could not allocate extradata\n");
|
||||
return false;
|
||||
}
|
||||
LogInfo("Found extradata\n");
|
||||
memcpy(extradata, pData, i);
|
||||
mStream->codecpar->extradata = extradata;
|
||||
mStream->codecpar->extradata_size = i;
|
||||
mStreamHeaderWritten = true;
|
||||
return mStreamHeaderWritten;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void FfmpegOutputStream::GetDecodeDataCallback(AVFrame *frame)
|
||||
{
|
||||
mEncoder->EncodeData(frame, mStream, mEncodeCallback);
|
||||
}
|
||||
void FfmpegOutputStream::GetEncodeDataCallback(AVPacket *pkt)
|
||||
{
|
||||
if (mEncoder) {
|
||||
mEncoder->EncodeData(frame, mStream, mEncodeCallback);
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -45,10 +45,10 @@ public:
|
|||
void UnInit(void);
|
||||
void WriteSourceData(const void *data, const size_t &size);
|
||||
void SetWriteSourceDataCallback(std::function<void(AVPacket *pkt)> callback);
|
||||
bool CheckStreamHeader(const void *data, const size_t &size);
|
||||
|
||||
private:
|
||||
void GetDecodeDataCallback(AVFrame *frame);
|
||||
void GetEncodeDataCallback(AVPacket *pkt);
|
||||
|
||||
private:
|
||||
const AVCodecID mEncodecId;
|
||||
|
@ -59,5 +59,6 @@ private:
|
|||
AVStream *mStream;
|
||||
std::function<void(AVFrame *)> mDecodeCallback;
|
||||
std::function<void(AVPacket *)> mEncodeCallback;
|
||||
bool mStreamHeaderWritten;
|
||||
};
|
||||
#endif
|
|
@ -60,6 +60,7 @@ StatusCode FfmpegReadFile::StartReadFile(const std::string &path)
|
|||
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
|
||||
if (pFormatCtx->streams[i]->codecpar->codec_type == mFFmpegMediaType) {
|
||||
mediaStreamIndex = i;
|
||||
LogInfo("Find stream index=%s.\n", avcodec_get_name(pFormatCtx->streams[i]->codecpar->codec_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user