gpt4 book ai didi

c - 使用 ffmpeg 和 sdl2 进行口吃渲染

转载 作者:行者123 更新时间:2023-12-04 22:58:05 24 4
gpt4 key购买 nike

使用以下代码,我得到了电影文件的口吃渲染。有趣的是,当用 ffmpeg 转储信息时,它说它有 25 fps 和 00:01:32.90 的持续时间;然而,当计算帧数和它自己运行的时间时,它给出了大约 252 秒的时间,我猜接收帧和发送包的代码 (int cap(vid v)) 多次绘制相同的帧。但我看不出有什么问题?

//PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:/usr/lib64/pkgconfig/   --> add path to PKF_Config search path
//export PKG_CONFIG_PATH --> export PKG_Config search path to become visible for gcc
//gcc ffmpeg_capture_fl.c -Wall -pedantic -fPIC `pkg-config --cflags --libs libavdevice libavformat libavcodec libavutil libavdevice libavfilter libswscale libswresample sdl2`


#include <libavdevice/avdevice.h>
#include <libavutil/opt.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <stdio.h>
#include <stdlib.h>
#include <libavutil/rational.h>
#include <sys/time.h>
#include <unistd.h>


typedef struct vid{
AVFormatContext *inc;
AVInputFormat *iformat;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
int videoStream;} vid;

typedef struct sws{
struct SwsContext *ctx;
uint8_t **buffer;
int *linesize;
} sws;


vid cap_init_fl(char *fl);
int cap(vid v);
void cap_close(vid v);

sws init_swsctx(int width, int height, enum AVPixelFormat pix_fmt, int new_width, int new_height, enum AVPixelFormat new_pxf);
void conv_pxlformat(sws scale, uint8_t **src_data, int *src_linesize, int height);
void free_sws(sws inp);

#include <SDL2/SDL.h>

typedef struct sdl_window{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
SDL_Event *event;
int width;
int height;
int pitch;
uint32_t sdl_pxl_frmt;
}sdl_window;

sdl_window init_windowBGR24_ffmpg(int width, int height);
int render_on_texture_update(sdl_window wow, uint8_t *data);
void close_window(sdl_window wow);


vid cap_init_fl(char *fl){
vid v = {NULL, NULL, NULL, NULL, NULL, -1};
int i;

av_register_all();
avdevice_register_all();

if( 0 > avformat_open_input( &(v.inc), fl , v.iformat, NULL)) {
printf("Input device could not been opened\n");
cap_close(v);
exit(1);
}

if(avformat_find_stream_info(v.inc, NULL)<0){
printf("Stream information could not been found.\n");
cap_close(v);
exit(2);
}

// Dump information about file onto standard error
av_dump_format(v.inc, 0, fl, 0);

// Find the first video stream
v.videoStream=-1;
for(i=0; i<v.inc->nb_streams; i++){
if(v.inc->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) {
v.videoStream=i;
break;
}}

if(v.videoStream==-1){
printf("Could not find video stream.\n");
cap_close(v);
exit(3);
}

// Find the decoder for the video stream
v.pCodec=avcodec_find_decoder(v.inc->streams[v.videoStream]->codecpar->codec_id);
if(v.pCodec==NULL) {
printf("Unsupported codec!\n");
cap_close(v);
exit(4);
// Codec not found
}



// Get a pointer to the codec context for the video stream

if((v.pCodecCtx=avcodec_alloc_context3(NULL)) == NULL){
printf("Could not allocate codec context\n");
cap_close(v);
exit(10);}

avcodec_parameters_to_context (v.pCodecCtx, v.inc->streams[v.videoStream]->codecpar);

// Open codec
if(avcodec_open2(v.pCodecCtx, v.pCodec, NULL)<0){
printf("Could not open codec");
cap_close(v);
exit(5);
}


// Allocate video frame
v.pFrame=av_frame_alloc();
if(v.pFrame==NULL){
printf("Could not allocate AVframe");
cap_close(v);
exit(6);}


return v;
}



int cap(vid v){
int errorCodeRF, errorCodeSP, errorCodeRecFR;
AVPacket pkt;

if((errorCodeRF = av_read_frame(v.inc, &pkt)) >= 0){

if (pkt.stream_index == v.videoStream) {

errorCodeSP = avcodec_send_packet(v.pCodecCtx, &pkt);

if (errorCodeSP >= 0 || errorCodeSP == AVERROR(EAGAIN)){

errorCodeRecFR = avcodec_receive_frame(v.pCodecCtx, v.pFrame);

if (errorCodeRecFR < 0){
av_packet_unref(&pkt);
return errorCodeRecFR;
}
else{
av_packet_unref(&pkt);
return 0;
}

}
else{
av_packet_unref(&pkt);
return errorCodeSP;}

}}

else{
return errorCodeRF;}
return 1;
}



void cap_close(vid v){
if(v.pFrame != NULL) av_free(v.pFrame);
avcodec_close(v.pCodecCtx);
avformat_close_input(&(v.inc));
if(v.inc != NULL) avformat_free_context(v.inc);

v.inc = NULL;
v.iformat = NULL;
v.pCodecCtx = NULL;
v.pCodec = NULL;
v.pFrame = NULL;
v.videoStream=-1;}



sws init_swsctx(int width, int height, enum AVPixelFormat pix_fmt, int new_width, int new_height, enum AVPixelFormat new_pxf){

int nwidth, nheight;
sws scale;

scale.buffer = (uint8_t **) malloc(4 * sizeof(uint8_t *));
scale.linesize = (int *) malloc(4 * sizeof(int));


nwidth = (new_width <= 0) ? width : new_width;
nheight = (new_height <= 0) ? height : new_height;

av_image_alloc(scale.buffer, scale.linesize, nwidth, nheight, new_pxf, 1);
scale.ctx = sws_getContext(width, height, pix_fmt, nwidth, nheight, new_pxf, SWS_BILINEAR, NULL, NULL, NULL);

if(scale.ctx==NULL){
printf("Could not allocate SWS-Context\n");
av_freep(&(scale.buffer)[0]);
free(scale.buffer);
free(scale.linesize);
exit(12);
}

return scale;}


void conv_pxlformat(sws scale, uint8_t **src_data, int *src_linesize, int height){
sws_scale(scale.ctx, (const uint8_t **) src_data, src_linesize, 0, height, scale.buffer, scale.linesize);
}


void free_sws(sws inp){
av_freep(&(inp.buffer)[0]);
free(inp.buffer);
free(inp.linesize);
}


sdl_window init_windowBGR24_ffmpg(int width, int height){

sdl_window wow;

if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Couldn't initialize SDL in function: create_sdl_window(...)\n");
exit(7);}

wow.window = SDL_CreateWindow("SDL_CreateTexture",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_RESIZABLE);

wow.renderer = SDL_CreateRenderer(wow.window, -1, SDL_RENDERER_ACCELERATED);
wow.texture = SDL_CreateTexture(wow.renderer, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, width, height);
wow.width = width;
wow.height = height;
wow.pitch = width * 3; //only true for 3 byte / 24bit packed formats like bgr24
wow.sdl_pxl_frmt = SDL_PIXELFORMAT_BGR24;
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "enable");
SDL_RenderSetLogicalSize(wow.renderer, wow.width, wow.height);
return wow;
}


int render_on_texture_update(sdl_window wow, uint8_t *data){

if (SDL_UpdateTexture(wow.texture, NULL, data, wow.pitch)< 0){
printf("SDL_render_on_texture_update_failed: %s\n", SDL_GetError());
return -1;
}
SDL_RenderClear(wow.renderer);
SDL_RenderCopy(wow.renderer, wow.texture, NULL, NULL);
SDL_RenderPresent(wow.renderer);

return 0;
}


void close_window(sdl_window wow){
SDL_DestroyRenderer(wow.renderer);
SDL_Quit();
}




int main(){
int n, vid_error;
long int time_per_frame_usec, duration_usec;
vid v;
sdl_window wow;
struct timeval tval_start, tval_start1, tval_end, tval_duration;
sws scale;
SDL_Event event;

vid_error = AVERROR(EAGAIN);
v = cap_init_fl("mw_maze_test.mp4");

while(vid_error == AVERROR(EAGAIN)){
vid_error =cap(v);}

if(vid_error < 0){
printf("Could not read from Capture\n");
cap_close(v);
return 0;
}

wow = init_windowBGR24_ffmpg((v.pCodecCtx)->width, (v.pCodecCtx)->height);
scale = init_swsctx((v.pCodecCtx)->width, (v.pCodecCtx)->height, (v.pCodecCtx)->pix_fmt, 0, 0, AV_PIX_FMT_BGR24);

time_per_frame_usec = ((long int)((v.inc)->streams[v.videoStream]->avg_frame_rate.den) * 1000000 / (long int) ((v.inc)->streams[v.videoStream]->avg_frame_rate.num));

printf("Time per frame: %ld\n", time_per_frame_usec);
n = 0;

gettimeofday(&tval_start, NULL);
gettimeofday(&tval_start1, NULL);

while ((vid_error =cap(v)) >= 0) {

if (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT)
break;}

conv_pxlformat(scale, (v.pFrame)->data, (v.pFrame)->linesize, (v.pCodecCtx)->height);
gettimeofday(&tval_end, NULL);
timersub(&tval_end, &tval_start, &tval_duration);
duration_usec = (long int)tval_duration.tv_sec * 1000000 + (long int)tval_duration.tv_usec;

while(duration_usec < time_per_frame_usec) {
gettimeofday(&tval_end, NULL);
timersub(&tval_end, &tval_start, &tval_duration);
duration_usec = (long int)tval_duration.tv_sec * 1000000 + (long int)tval_duration.tv_usec;
}

gettimeofday(&tval_start, NULL);
render_on_texture_update(wow, *(scale.buffer));
n++;
}

gettimeofday(&tval_end, NULL);
timersub(&tval_end, &tval_start1, &tval_duration);
duration_usec = (long int)tval_duration.tv_sec * 1000000 + (long int)tval_duration.tv_usec;

printf("Total time and frames; %ld %i\n", duration_usec, n);

if(vid_error == AVERROR(EAGAIN)){
printf("AVERROR(EAGAIN) occured\n)");
}


sws_freeContext(scale.ctx);
free_sws(scale);
close_window(wow);
cap_close(v);
return 0;
}

the output is:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'mw_maze_test.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: isommp42
creation_time : 2014-02-14T21:09:52.000000Z
Duration: 00:01:32.90, start: 0.000000, bitrate: 347 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 384x288 [SAR 1:1 DAR 4:3], 249 kb/s, 25 fps, 25 tbr, 25 tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 96 kb/s (default)
Metadata:
creation_time : 2014-02-14T21:09:53.000000Z
handler_name : IsoMedia File Produced by Google, 5-11-2011
Time per frame: 40000
Total time and frames; 252881576 6322


最佳答案

发布后一分钟就想通了。问题是 (int cap(vid v))当帧不是视频帧(因此是音频帧)时返回 1。每次从 cap >= 0 返回时,main 中的 while 循环都会运行。因此对于音频帧也是如此,因此需要将主循环更改为仅在从视频帧返回时运行:

while ((vid_error =cap(v)) >= 0) {
if(vid_error == 0){
// code as before
}}...

关于c - 使用 ffmpeg 和 sdl2 进行口吃渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65406881/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com