sách gpt4 ai đã đi

c++ - 如何使用 ffmpeg 在 C 代码中从 png 中创建带有 alpha 的视频?

In lại 作者:行者123 更新时间:2023-12-04 23:35:01 25 4
mua khóa gpt4 Nike

我正在尝试使用 FFMPEG 中的 alpha channel 从 png 图像中编码视频(mov)。使用命令:

ffmpeg -i %d.png -r 25 -vcodec png -b:v 2500K out.mov -y
它运作良好。
现在我想在 C++ 代码中使用,但它得到了这样的错误:
[mov @ 0x29bf0c0] muxer does not support non seekable output
我在这样的代码中使用它:
oformat = av_guess_format("mov", nullptr, nullptr)
oformat->video_codec = AV_CODEC_ID_PNG;
ffmpeg 显示:
ffmpeg -h muxer=mov
Muxer mov [QuickTime / MOV]:
Common extensions: mov.
Default video codec: h264.
Default audio codec: aac.
默认的视频编解码器是 h264,但它可以使用上面的 ffmpeg 命令行使用 png 编码器创建 mov
ffmpeg -i out.mov

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'resa.mov':
Metadata:
major_brand : qt
minor_version : 512
compatible_brands: qt
encoder : Lavf59.24.100
Duration: 00:00:03.00, start: 0.000000, bitrate: 13430 kb/s
Stream #0:0: Video: png (png / 0x20676E70), rgba(pc), 1280x720, 13427 kb/s, 25 fps, 25 tbr, 12800 tbn, 12800 tbc (default)
Metadata:
handler_name : VideoHandler
vendor_id : FFMP
如何将此 cmd 更改为 c 代码?
ffmpeg -i %d.png -r 25 -vcodec png -b:v 2500K out.mov -y
我使用的代码:
头文件:
#ifndef _RENDER_H_
#define _RENDER_H_
#include
#include
#include
#include
#include
#include
#include
#include
#include

extern "C"
{
#include
#include

#include

#include
//#include
#include
#include

#include
#include



#include
#include
#include
#include
#include
#include
#include
#include
#include
#include



//#include "libavcodec/vdpau.h"
#include "libavutil/hwcontext.h"
//#include "libavutil/hwcontext_vdpau.h"



#include

class VideoCapture {
công cộng:

VideoCapture() {
oformat = nullptr;
ofctx = nullptr;
videoStream = nullptr;
videoFrame = nullptr;
swsCtx = nullptr;
frameCounter = 0;


av_register_all();
//av_log_set_callback(avlog_cb);
}

~VideoCapture() {
//Free();
}

void Init(std::string name, int width, int height, int fpsrate, int bitrate);

void AddFrame(uint8_t *data);

void Finish();

riêng tư:

AVOutputFormat *oformat;
AVFormatContext *ofctx;
AVIOContext *avio_out;
AVStream *videoStream;
AVFrame *videoFrame;

AVCodec *codec;
AVCodecContext *cctx;
struct buffer_data *bd;
struct buffer_data* res_video;
SwsContext *swsCtx;
//FILE *fp_write;
char* filename;
//int buf_len;
int frameCounter;

int fps;

void Free();

void Remux();
};

struct buffer_data {
uint8_t *ptr;
size_t size; ///< size left in the buffer
};

}
#kết thúc nếu
和代码:
#include "VideoCapture.h"
#define FINAL_FILE_NAME "record.mov"
#define VIDEO_TMP_FILE "tmp.avi"


sử dụng không gian tên std;

FILE *fp_write;
static int write_packet(void *opaque, uint8_t *buf, size_t buf_size)
{
struct buffer_data *bd = (struct buffer_data *)opaque;
printf("ptr :%p size:%zu\n", bd->ptr, bd->size);
memcpy(bd->ptr + bd->size, buf, buf_size);
bd->size = buf_size + bd->size;
return 1;
}

void VideoCapture::Init(string filename, int width, int height, int fpsrate, int bitrate) {

fps = fpsrate;

int err;
uint8_t *outbuffer=nullptr;
outbuffer=(uint8_t*)av_malloc(32768);
bd = (struct buffer_data*)malloc(sizeof(struct buffer_data));
bd->ptr = (uint8_t*)av_malloc(1000000000);
bd->size = 0;
avio_out =avio_alloc_context(outbuffer, 32768,1,bd,nullptr,write_packet,nullptr);
if (!(oformat = av_guess_format("mov", nullptr, nullptr))) {
cout << "Failed to define output format"<< endl;
return;
}
oformat->video_codec = AV_CODEC_ID_PNG;
cout << "oformat->video_codec " << oformat->video_codec << endl;
if ((err = avformat_alloc_output_context2(&ofctx, oformat, nullptr, nullptr) < 0)) {
cout <<"Failed to allocate output context"<< endl;
//Free();
return;
}
cout << "oformat->video_codec " << oformat->video_codec << endl;
if (!(codec = avcodec_find_encoder(oformat->video_codec))) {
cout <<"Failed to find encoder"<< endl;
//Free();
return;
}

if (!(videoStream = avformat_new_stream(ofctx, codec))) {
cout <<"Failed to create new stream"<< endl;
//Free();
return;
}

if (!(cctx = avcodec_alloc_context3(codec))) {
cout <<"Failed to allocate codec context"<< endl;
//Free();
return;
}

videoStream->codecpar->codec_id = oformat->video_codec;
videoStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
videoStream->codecpar->width = width;
videoStream->codecpar->height = height;
videoStream->codecpar->format = AV_PIX_FMT_RGBA;
videoStream->codecpar->bit_rate = bitrate * 1000;
videoStream->time_base = { 1, fps };

avcodec_parameters_to_context(cctx, videoStream->codecpar);
cctx->time_base = { 1, fps };
cctx->max_b_frames = 2;
cctx->gop_size = 12;
if (videoStream->codecpar->codec_id == AV_CODEC_ID_PNG) {
//av_opt_set(cctx, "preset", "ultrafast", 0);
}
if (ofctx->oformat->flags & AVFMT_GLOBALHEADER) {
cctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
avcodec_parameters_from_context(videoStream->codecpar, cctx);

if ((err = avcodec_open2(cctx, codec, nullptr)) < 0) {
cout <<"Failed to open codec"<< endl;
Free();
return;
}

ofctx->pb = avio_out;

ofctx->flags=AVFMT_FLAG_CUSTOM_IO;
if ((err = avformat_write_header(ofctx, nullptr)) < 0) {
cout <<"Failed to write header"<< endl;
Free();
return;
}

//av_dump_format(ofctx, 0, VIDEO_TMP_FILE, 1);
cout << "init com" << endl;
}

void VideoCapture::AddFrame(uint8_t *data) {
int err;
if (!videoFrame) {

videoFrame = av_frame_alloc();
videoFrame->format = AV_PIX_FMT_RGBA;
videoFrame->width = cctx->width;
videoFrame->height = cctx->height;

if ((err = av_frame_get_buffer(videoFrame, 32)) < 0) {
cout <<"Failed to allocate picture"<< endl;
return;
}
}
cout << "finish" << endl;
if (!swsCtx) {
swsCtx = sws_getContext(cctx->width, cctx->height, AV_PIX_FMT_RGBA, cctx->width, cctx->height, AV_PIX_FMT_RGBA, SWS_BICUBIC, 0, 0, 0);
}

int inLinesize[1] = { 4 * cctx->width};


sws_scale(swsCtx, (const uint8_t * const *)&data, inLinesize, 0, cctx->height, videoFrame->data, videoFrame->linesize);

videoFrame->pts = (1.0 / 30.0) * 90000 * (frameCounter++);;

if ((err = avcodec_send_frame(cctx, videoFrame)) < 0) {
cout <<"Failed to send frame"<< endl;
return;
}

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;

if (avcodec_receive_packet(cctx, &pkt) == 0) {
pkt.flags |= AV_PKT_FLAG_KEY;
av_interleaved_write_frame(ofctx, &pkt);
av_packet_unref(&pkt);
}
}

void VideoCapture::Finish() {

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;

for (;;) {
avcodec_send_frame(cctx, nullptr);
if (avcodec_receive_packet(cctx, &pkt) == 0) {
av_interleaved_write_frame(ofctx, &pkt);
av_packet_unref(&pkt);
}
else {
phá vỡ;
}
}


av_write_trailer(ofctx);
/*
if (!(oformat->flags & AVFMT_NOFILE)) {
int err = avio_close(ofctx->pb);
if (err < 0) {
cout <<"Failed to close file"<< endl;
}
}
*/
fp_write = fopen(VIDEO_TMP_FILE, "wb");
if (!feof(fp_write)) {
int true_size = fwrite(bd->ptr, 1, bd->size, fp_write);
std::cout << true_size << std::endl;
}
fcloseall();

//Remux();
//Free();
}

void VideoCapture::Free() {
if (videoFrame) {
//std::cout << "videoFrame " << std::endl;
av_frame_free(&videoFrame);
}
if (cctx) {
//std::cout << "cctx" << std::endl;
avcodec_free_context(&cctx);
}
if (ofctx) {
//std::cout << "ofctx" << ofctx << std::endl;
avformat_free_context(ofctx);
}
if (swsCtx) {
//std::cout << "swsCtx" << std::endl;
sws_freeContext(swsCtx);
}
/*
if (bd->ptr != (void*)0)
{
free(bd->ptr);
}
free(bd);*/
}

static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
struct buffer_data *bd = (struct buffer_data *)opaque;
buf_size = FFMIN(buf_size, bd->size);
if(buf_size == 0) return -1;
//printf("read ptr:%p size:%zu\n", bd->ptr, bd->size);
/* copy internal buffer data to buf */
memcpy(buf, bd->ptr, buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;
return buf_size;
}

void VideoCapture::Remux() {
AVFormatContext *ifmt_ctx = nullptr, *ofmt_ctx = nullptr;
int err;

unsigned char* inbuffer=nullptr;
inbuffer=(unsigned char*)av_malloc(32768);
ifmt_ctx = avformat_alloc_context();
AVIOContext *avio_in =avio_alloc_context(inbuffer, 32768 ,0,bd,read_packet,nullptr,nullptr);
ifmt_ctx->pb=avio_in;

if (!(oformat = av_guess_format(nullptr, nullptr, "h264"))) {
cout << "Failed to define output format";
return;
}

if ((err = avformat_open_input(&ifmt_ctx, "nullptr", 0, 0)) < 0) {
cout <<"Failed to open input file for remuxing"<< endl;
}
if ((err = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
cout <<"Failed to retrieve input stream information"<< endl;
}
if ((err = avformat_alloc_output_context2(&ofmt_ctx, oformat, nullptr, nullptr))) {
cout <<"Failed to allocate output context"<< endl;
}

AVStream *inVideoStream = ifmt_ctx->streams[0];
AVStream *outVideoStream = avformat_new_stream(ofmt_ctx, nullptr);
if (!outVideoStream) {
cout <<"Failed to allocate output video stream" << endl;
}
outVideoStream->time_base = { 1, fps };
avcodec_parameters_copy(outVideoStream->codecpar, inVideoStream->codecpar);
outVideoStream->codecpar->codec_tag = 0;

uint8_t *outbuffer=nullptr;
outbuffer=(uint8_t*)av_malloc(32768);
res_video = (struct buffer_data*)malloc(sizeof(struct buffer_data));
res_video->ptr = (uint8_t*)av_malloc(100000000);
res_video->size = 0;

if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_out =avio_alloc_context(outbuffer, 32768,1, res_video, nullptr, write_packet, nullptr);
ofmt_ctx->pb = avio_out;
}
AVDictionary* opts = nullptr;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
if ((err = avformat_write_header(ofmt_ctx, &opts)) < 0) {
cout <<"Failed to write header to output file"<< endl;
}

AVPacket videoPkt;
int ts = 0;
while (true) {
if ((err = av_read_frame(ifmt_ctx, &videoPkt)) < 0) {
phá vỡ;
}
videoPkt.stream_index = outVideoStream->index;
videoPkt.pts = ts;
videoPkt.dts = ts;
videoPkt.duration = av_rescale_q(videoPkt.duration, inVideoStream->time_base, outVideoStream->time_base);
ts += videoPkt.duration;
videoPkt.pos = -1;
if ((err = av_interleaved_write_frame(ofmt_ctx, &videoPkt)) < 0) {
cout <<"Failed to mux packet"<< endl;
av_packet_unref(&videoPkt);
phá vỡ;
}
av_packet_unref(&videoPkt);
}

av_write_trailer(ofmt_ctx);
cout << "res_video->size " << res_video->size << endl;
fp_write=fopen(FINAL_FILE_NAME,"wb");
if(!feof(fp_write)){
int true_size=fwrite(res_video->ptr,1, res_video->size,fp_write);
std::cout << true_size << std::endl;
}
fcloseall();
}

1 Câu trả lời

我已经解决了这个问题。 Ffmpeg 显示 muxer mov 支持视频编解码器 h264。所以我使用了支持vp9的webm。并且vp9支持yuva420p

Muxer webm [WebM]:
Common extensions: webm.
Mime type: video/webm.
Default video codec: vp9.
Default audio codec: vorbis.
Default subtitle codec: webvtt.

Encoder libvpx-vp9 [libvpx VP9]:
General capabilities: delay threads
Threading capabilities: other
Supported pixel formats: yuv420p yuva420p yuv422p yuv440p yuv444p yuv420p10le yuv422p10le yuv440p10le yuv444p10le yuv420p12le yuv422p12le yuv440p12le yuv444p12le gbrp gbrp10le gbrp12le
我更改代码
oformat = av_guess_format("mov", nullptr, nullptr)
ĐẾN
oformat = av_guess_format("webm", nullptr, nullptr)
注意:解码webm时。原生 VP8/9 解码器不解码 alpha,但 libvpx 可以,并且 ffprobe 在可用时使用原生解码器作为流。目前,没有工具可以为流强制使用特定的解码器。因此您必须使用解码器 libvpx-vp9。像这样:
ffmpeg -vcodec libvpx-vp9 -i tmp.webm img_%04d.png
或在代码中:
AVCodec* pCodec = avcodec_find_decoder_by_name("libvpx-vp9");
见票:
VP9 will not encode in yuva420p
ffprobe does not recognize yuva420p format (alpha channel) for webm

关于c++ - 如何使用 ffmpeg 在 C 代码中从 png 中创建带有 alpha 的视频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72527050/

25 4 0
行者123
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com