
Recherche avancée
Autres articles (77)
-
Le profil des utilisateurs
12 avril 2011, parChaque utilisateur dispose d’une page de profil lui permettant de modifier ses informations personnelle. Dans le menu de haut de page par défaut, un élément de menu est automatiquement créé à l’initialisation de MediaSPIP, visible uniquement si le visiteur est identifié sur le site.
L’utilisateur a accès à la modification de profil depuis sa page auteur, un lien dans la navigation "Modifier votre profil" est (...) -
Configurer la prise en compte des langues
15 novembre 2010, parAccéder à la configuration et ajouter des langues prises en compte
Afin de configurer la prise en compte de nouvelles langues, il est nécessaire de se rendre dans la partie "Administrer" du site.
De là, dans le menu de navigation, vous pouvez accéder à une partie "Gestion des langues" permettant d’activer la prise en compte de nouvelles langues.
Chaque nouvelle langue ajoutée reste désactivable tant qu’aucun objet n’est créé dans cette langue. Dans ce cas, elle devient grisée dans la configuration et (...) -
XMP PHP
13 mai 2011, parDixit Wikipedia, XMP signifie :
Extensible Metadata Platform ou XMP est un format de métadonnées basé sur XML utilisé dans les applications PDF, de photographie et de graphisme. Il a été lancé par Adobe Systems en avril 2001 en étant intégré à la version 5.0 d’Adobe Acrobat.
Étant basé sur XML, il gère un ensemble de tags dynamiques pour l’utilisation dans le cadre du Web sémantique.
XMP permet d’enregistrer sous forme d’un document XML des informations relatives à un fichier : titre, auteur, historique (...)
Sur d’autres sites (11186)
-
closed (H264 track 1 is not valid : sprop-parameter-sets is missing (96 packetization-mode=1)
8 janvier 2024, par MMingYI used FFmpeg6.1 to stream RTSP, but I received the following errors on the server :




closed (H264 track 1 is not valid : sprop-parameter-sets is missing (96 packetization-mode=1),client:Error occurred when opening output Server returned 400 Bad Request.




#include 
#include 
#include 

#include <libavcodec></libavcodec>avcodec.h>
#include <libavformat></libavformat>avformat.h>
#include <libavutil></libavutil>opt.h>
#include <libavutil></libavutil>imgutils.h>
#include <libavutil></libavutil>time.h>

static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
 AVFormatContext *outFormatCtx) {
 int ret;

 /* send the frame to the encoder */
 if (frame)
 printf("Send frame %3"PRId64"\n", frame->pts);

 ret = avcodec_send_frame(enc_ctx, frame);
 if (ret < 0) {
 char errbuf[AV_ERROR_MAX_STRING_SIZE];
 av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
 fprintf(stderr, "Error sending a frame for encoding ,%s\n", errbuf);
 exit(1);
 }

 while (ret >= 0) {
 ret = avcodec_receive_packet(enc_ctx, pkt);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
 return;
 else if (ret < 0) {
 fprintf(stderr, "Error during encoding\n");
 exit(1);
 }

 printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
 av_write_frame(outFormatCtx, pkt); // Write the packet to the RTMP stream
 av_packet_unref(pkt);
 }
}

int main(int argc, char **argv) {
 av_log_set_level(AV_LOG_DEBUG);
 const char *rtmp_url, *codec_name;
 const AVCodec *codec;
 AVCodecContext *codecContext = NULL;
 int i, ret, x, y;
 AVFormatContext *outFormatCtx;
 AVStream *st;
 AVFrame *frame;
 AVPacket *pkt;
 uint8_t endcode[] = {0, 0, 1, 0xb7};

 if (argc <= 3) {
 fprintf(stderr, "Usage: %s <rtmp url="url"> <codec>\n", argv[0]);
 exit(0);
 }
 rtmp_url = argv[1];
 codec_name = argv[2];
 avformat_network_init();
 /* find the mpeg1video encoder */
// codec = avcodec_find_encoder_by_name(codec_name);
// codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
// codec = avcodec_find_encoder(AV_CODEC_ID_VP9);
// codec = avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO);
 codec = avcodec_find_encoder(AV_CODEC_ID_H264);
// codec = avcodec_find_encoder(AV_CODEC_ID_AV1);
// codec = avcodec_find_encoder(AV_CODEC_ID_H265);
 if (!codec) {
 fprintf(stderr, "Codec '%s' not found\n", codec_name);
 exit(1);
 }
 codecContext = avcodec_alloc_context3(codec);
 if (!codecContext) {
 fprintf(stderr, "Could not allocate video codec context\n");
 exit(1);
 }

 /* ... (rest of the setup code) ... */
/* put sample parameters */
 codecContext->bit_rate = 400000;
 /* resolution must be a multiple of two */
 codecContext->width = 352;
 codecContext->height = 288;
 /* frames per second */
 codecContext->time_base = (AVRational) {1, 25};
 codecContext->framerate = (AVRational) {25, 1};

 /* emit one intra frame every ten frames
 * check frame pict_type before passing frame
 * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
 * then gop_size is ignored and the output of encoder
 * will always be I frame irrespective to gop_size
 */
 codecContext->gop_size = 10;
 codecContext->max_b_frames = 1;
 codecContext->pix_fmt = AV_PIX_FMT_YUV420P;



 /* Open the RTSP output */
// const AVOutputFormat *ofmt = av_guess_format("tcp", NULL, NULL);
 const AVOutputFormat *ofmt = av_guess_format("rtsp", rtmp_url, NULL);
// const AVOutputFormat *ofmt = av_guess_format("flv", NULL, NULL);
// const AVOutputFormat *ofmt = av_guess_format("rtmp", NULL, NULL);
// const AVOutputFormat *ofmt = av_guess_format("mpegts", NULL, NULL);
// const AVOutputFormat *ofmt = av_guess_format("mp4", NULL, NULL);
 if (!ofmt) {
 fprintf(stderr, "Could not find output format\n");
 exit(1);
 }

 /* Allocate the output context */

/* outFormatCtx = avformat_alloc_context();
 if (!outFormatCtx) {
 fprintf(stderr, "Could not allocate output context\n");
 exit(1);
 }*/

 // 打开输出 这个会导致outFormatCtx 中的stream 为空,并且产生这个问题[rtsp @ 00000204f6218b80] No streams to mux were specified
 if (avformat_alloc_output_context2(&outFormatCtx, ofmt, "rtsp", rtmp_url) != 0) {
 fprintf(stderr, "Could not allocate output context\n");
 return 1;
 }


 outFormatCtx->oformat = ofmt;
 outFormatCtx->url = av_strdup(rtmp_url);

 /* Add a video stream */
 st = avformat_new_stream(outFormatCtx, codec);
 if (!st) {
 fprintf(stderr, "Could not allocate stream\n");
 exit(1);
 }
 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
 st->codecpar->codec_id = codec->id;
 st->codecpar->width = 352;
 st->codecpar->height = 288;
 st->codecpar->format = AV_PIX_FMT_YUV420P;
// st->codecpar = c;
// st->codecpar->format = AV_PIX_FMT_YUV420P;
 // Set video stream parameters
// st->codecpar->framerate = (AVRational) {25, 1};
// st->id=outFormatCtx->nb_streams-1;
 /* Set the output URL */
 av_dict_set(&outFormatCtx->metadata, "url", rtmp_url, 0);


 pkt = av_packet_alloc();
 if (!pkt)
 exit(1);


 if (codec->id == AV_CODEC_ID_H264)
 av_opt_set(codecContext->priv_data, "preset", "slow", 0);

 AVDictionary *opt = NULL;
/* av_dict_set(&opt, "rtsp_transport", "udp", 0);
 av_dict_set(&opt, "announce_port", "1935", 0);
 av_dict_set(&opt, "enable-protocol", "rtsp", 0);
 av_dict_set(&opt, "protocol_whitelist", "file,udp,tcp,rtp,rtsp", 0);
 av_dict_set(&opt, "enable-protocol", "rtp", 0);
 av_dict_set(&opt, "enable-protocol", "rtsp", 0);
 av_dict_set(&opt, "enable-protocol", "udp", 0);
 av_dict_set(&opt, "enable-muxer", "rtsp", 0);
 av_dict_set(&opt, "enable-muxer", "rtp", 0);*/
 av_dict_set(&opt, "rtsp_transport", "tcp", 0);
 av_dict_set(&opt, "stimeout", "2000000", 0);
 av_dict_set(&opt, "max_delay", "500000", 0);
 av_dict_set(&opt, "sprop-parameter-sets", "asdgasdfs", AV_DICT_APPEND);
 /* open it */
 ret = avcodec_open2(codecContext, codec, &opt);
 if (ret < 0) {
 fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
 exit(1);
 }
/* // 打开RTSP输出URL 微软AI给出的代码
 if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE)) {
 int ret = avio_open(&outFormatCtx->pb, rtmp_url, AVIO_FLAG_WRITE);
 if (ret < 0) {
// std::cerr << "Could not open output URL " << out_url << std::endl;
 fprintf(stderr, "Could not open output URL %s\n", av_err2str(ret));
 return -1;
 }
 }*/

 avcodec_parameters_to_context(codecContext, st->codecpar);

/* AVDictionary *options = NULL;
 av_dict_set(&options, "rtsp_transport", "tcp", 0);
 av_dict_set(&options, "stimeout", "2000000", 0);
 av_dict_set(&options, "max_delay", "500000", 0);
 // 初始化输出
 av_dict_set(&options, "rtsp_transport", "tcp", 0);
//设置 接收包间隔最大延迟,微秒
 av_dict_set(&options, "max_delay", "200000", 0);
// rtmp、rtsp延迟控制到最小
 av_dict_set(&options, "fflags", "nobuffer", 0);
// 在进行网络操作时允许的最大等待时间。5秒
 av_dict_set(&options, "timeout", "5000000", 0);
//设置 阻塞超时,否则可能在流断开时连接发生阻塞,微秒
 av_dict_set(&options, "stimeout", "3000000", 0);
//设置 find_stream_info 最大时长,微秒
 av_dict_set(&options, "analyzeduration", "1000000", 0);*/
 av_dict_set(&opt, "preset", "medium", 0);
 av_dict_set(&opt, "tune", "zerolatency", 0);
 av_dict_set(&opt, "profile", "baseline", 0);
 av_dump_format(outFormatCtx, 0, rtmp_url, 1);

 if (avformat_init_output(outFormatCtx, &opt) != 0) {
 fprintf(stderr, "Error initializing output\n");
 return 1;
 }
 if (!(ofmt->flags & AVFMT_NOFILE)) {
 ret = avio_open(&outFormatCtx->pb, rtmp_url, AVIO_FLAG_WRITE);
 if (ret < 0) {
 fprintf(stderr, "Could not open output file '%s'", rtmp_url);
 exit(1);
 }
 }
 /* 这种方式修改没有效果,无法添加修改SDP
 * av_dict_set(&st->metadata, "title", "Cool video", 0);
 av_dict_set(&st->metadata, "Content-Base", " rtsp://10.45.12.141/h264/ch1/main/av_stream/", 0);
 av_dict_set(&st->metadata, "sprop-parameter-sets", "sdsfwedeo", 0);*/
 AVCodecParameters *codecParams = st->codecpar;
 const char *spropParameterSets = "Z0IACpZTBYmI,aMlWsA=="; // 替换为实际的sprop-parameter-sets值
 av_dict_set(&st->metadata, "sprop-parameter-sets", spropParameterSets, 0);
 avcodec_parameters_to_context(codecContext, st->codecpar);
 AVFormatContext *avFormatContext[1];
 avFormatContext[0] = outFormatCtx;
 char spd[2048];
 av_sdp_create(avFormatContext, 1, spd, sizeof(spd));
 printf("%s\n", spd);
/* ret = avio_open(&outFormatCtx->pb, rtmp_url, AVIO_FLAG_WRITE);
 if (ret < 0) {
 fprintf(stderr, "Could not open output ,%s\n", av_err2str(ret));
 exit(1);
 }*/

/*// 设置 H264 参数
 AVDictionary *params = NULL;
 av_dict_set(&params, "profile", "main", 0);
 av_dict_set(&params, "level", "3.1", 0);

// 获取 `sprop-parameter-sets` 参数
 AVPacket *extradata = av_packet_alloc();
// avcodec_parameters_from_context(extradata->data, codecContext);

// 获取 `sprop-parameter-sets` 参数的大小
 int sprop_parameter_sets_size = extradata->size;

// 释放资源
 av_packet_free(&extradata);

// 设置 `sprop-parameter-sets` 参数
 uint8_t *sprop_parameter_sets = extradata->data;
 codecContext->extradata = sprop_parameter_sets;
 codecContext->extradata_size = sprop_parameter_sets_size;*/

 /* Write the header */
// ret = avformat_write_header(outFormatCtx, NULL);
 ret = avformat_write_header(outFormatCtx, &opt);
 if (ret != 0) {
 fprintf(stderr, "Error occurred when opening output %s\n", av_err2str(ret));
 exit(1);
 }

 frame = av_frame_alloc();
 if (!frame) {
 fprintf(stderr, "Could not allocate video frame\n");
 exit(1);
 }
// frame->format = c->pix_fmt;
// frame->format = AV_PIX_FMT_YUV420P;
 frame->format = 0;
 frame->width = codecContext->width;
 frame->height = codecContext->height;

 ret = av_frame_get_buffer(frame, 0);
 if (ret < 0) {
 fprintf(stderr, "Could not allocate the video frame data ,%s\n", av_err2str(ret));
 exit(1);
 }

 /* encode 1 second of video */
 for (i = 0; i < 2500; i++) {
 /* ... (rest of the encoding loop) ... */
 fflush(stdout);

 /* make sure the frame data is writable */
 ret = av_frame_make_writable(frame);
 if (ret < 0)
 exit(1);

 /* prepare a dummy image */
 /* Y */
 for (y = 0; y < codecContext->height; y++) {
 for (x = 0; x < codecContext->width; x++) {
 frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
 }
 }

 /* Cb and Cr */
 for (y = 0; y < codecContext->height / 2; y++) {
 for (x = 0; x < codecContext->width / 2; x++) {
 frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
 frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
 }
 }

 frame->pts = i;

 /* encode the image */
 encode(codecContext, frame, pkt, outFormatCtx);
 }

 /* flush the encoder */
 encode(codecContext, NULL, pkt, outFormatCtx);

 /* Write the trailer */
 av_write_trailer(outFormatCtx);

 /* Close the output */
 avformat_free_context(outFormatCtx);

 avcodec_free_context(&codecContext);
 av_frame_free(&frame);
 av_packet_free(&pkt);

 return 0;
}
</codec></rtmp>


I searched online for how to add "prop parameter sets", but I used their method but none of them worked. I also used WireShark to capture packets, but during the communication process, there was still no "prop parameter sets". Here is the method I tried :


AVDictionary *opt = NULL;
 av_dict_set(&opt, "sprop-parameter-sets", "asdgasdfs", 0);



-
Issues with FFMPEG swresample and channel mapping
19 mars 2024, par Joseph KatrinkaIve linked FFMPEG libs to a C++ project Im working on in VS2017 and have had mostly no problems with it so far.
Im currently trying to use it to extract audio from a movie file and save it as a wav file.
I managed to do this just fine, and my next step is to make a "split into mono". To make 2 mono wav files, one from the left channel and one from the right channel of a stereo file.
My code works for the orignal usecase, stereo to stereo (one wav file) and also works for when Im just doing the left, but when doing the right it fails.


Exception thrown at 0x00007FF9603F2D20 (swresample-4.dll) in Matchbox.exe : 0xC0000005 : Access violation reading location 0x0000000000000000.


This is the relevent code involved. It is failing inside the processing loop on line :

int ret = swr_convert_frame(swrCtx, resampledFrame, frame);


/// FFMPEG init
 AVFormatContext* formatCtx = nullptr;
 AVCodecContext* codecCtx = nullptr;
 const AVCodec* codec = nullptr;
 SwrContext* swrCtx = nullptr;
 AVPacket* packet = nullptr;
 AVFrame* frame = nullptr;
 AVFrame* resampledFrame = nullptr;
 int audioStreamIndex = -1;

 int sampleRate;

 uint64_t in_channel_layout = AV_CH_LAYOUT_STEREO; /// we only care about stereo in for now
 uint64_t out_channel_layout = doMono ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

 /// some redundancy in this stream setup/checking
 if (avformat_open_input(&formatCtx, movieFilePath.toRawUTF8(), nullptr, nullptr) < 0)
 {
 DBG("failed to open input file");
 return false;
 }
 if (avformat_find_stream_info(formatCtx, nullptr) < 0)
 {
 DBG("failed to find stream info");
 return false;
 }

 for (unsigned i = 0; i < formatCtx->nb_streams; i++) {
 if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
 {
 audioStreamIndex = i;
 break;
 }
 }
 if (audioStreamIndex == -1)
 {
 DBG("audio stream not found");
 return false;
 }

 codec = avcodec_find_decoder(formatCtx->streams[audioStreamIndex]->codecpar->codec_id);
 if (!codec)
 {
 DBG("decoder not found for audio stream");
 return false;
 }

 codecCtx = avcodec_alloc_context3(codec);
 if (avcodec_parameters_to_context(codecCtx, formatCtx->streams[audioStreamIndex]->codecpar) < 0)
 {
 DBG("failed to copy codec params to codec context");
 return false;
 }
 if (avcodec_open2(codecCtx, codec, nullptr) < 0)
 {
 DBG("failed to open codec");
 return false;
 }

 if (codecCtx->channels != 2)
 {
 DBG("unsupported channel layout");
 return false;
 }

 if (!codecCtx->channel_layout)
 {
 codecCtx->channel_layout = av_get_default_channel_layout(codecCtx->channels);
 }

 sampleRate = codecCtx->sample_rate; /// using this later for timecode calculation

 packet = av_packet_alloc();
 frame = av_frame_alloc();
 resampledFrame = av_frame_alloc();

 /// the input frame requires this info
 frame->format = codecCtx->sample_fmt;
 frame->channel_layout = codecCtx->channel_layout;
 frame->sample_rate = codecCtx->sample_rate;

 // does the resampled frame really need this?
 resampledFrame->format = AV_SAMPLE_FMT_S16;
 resampledFrame->channel_layout = out_channel_layout;
 resampledFrame->sample_rate = codecCtx->sample_rate;

 if (!packet || !frame || !resampledFrame)
 {
 DBG("failed to allocate packed or frame");
 return false;
 }

 /// Set up swrCtx for channel mapping if we need it
 swrCtx = swr_alloc();
 av_opt_set_int(swrCtx, "in_channel_layout", codecCtx->channel_layout, 0);
 av_opt_set_int(swrCtx, "out_channel_layout", out_channel_layout, 0);
 av_opt_set_int(swrCtx, "in_sample_rate", codecCtx->sample_rate, 0);
 av_opt_set_int(swrCtx, "out_sample_rate", codecCtx->sample_rate, 0);
 av_opt_set_sample_fmt(swrCtx, "in_sample_fmt", codecCtx->sample_fmt, 0);
 av_opt_set_sample_fmt(swrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

 /// channel mapping if we are doing mono
 if (doMono)
 {
 DBG("WE ARE DOING MONO");
 int in_channel_map[2];
 if (useLeft)
 {
 DBG("WE ARE DOING LEFT");
 in_channel_map[0] = AV_CH_FRONT_LEFT;
 }
 else
 {
 DBG("WE ARE DOING RIGHT");
 in_channel_map[0] = AV_CH_FRONT_RIGHT;
 }
 in_channel_map[1] = -1;
 swr_set_channel_mapping(swrCtx, in_channel_map);
 }
 

 if (swr_init(swrCtx) < 0)
 {
 DBG("failed to init resampler");
 return false;
 }

 AVFormatContext* outFormatCtx = nullptr;
 avformat_alloc_output_context2(&outFormatCtx, nullptr, nullptr, wavFilePath.toRawUTF8());
 if (!outFormatCtx)
 {
 DBG("failed to allocate output format context");
 return false;
 }

 AVStream* outStream = avformat_new_stream(outFormatCtx, nullptr);
 if (!outStream)
 {
 DBG("failed to create new stream for output");
 return false;
 }

 AVCodecContext* outCodecCtx = avcodec_alloc_context3(avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE));
 if (!outCodecCtx)
 {
 DBG("failed to allocate output codec context");
 return false;
 }

 outCodecCtx->sample_rate = codecCtx->sample_rate;
 outCodecCtx->channel_layout = out_channel_layout;
 outCodecCtx->channels = doMono ? 1 : 2;
 outCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
 outCodecCtx->bit_rate = 192000;
 outCodecCtx->time_base = (AVRational{ 1, outCodecCtx->sample_rate });

 if (avcodec_open2(outCodecCtx, avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE), nullptr) < 0)
 {
 DBG("failed to open output codec");
 return false;
 }

 outStream->time_base = outCodecCtx->time_base;
 if (avcodec_parameters_from_context(outStream->codecpar, outCodecCtx) < 0)
 {
 DBG("failed to copy codec params from context to stream");
 return false;
 }

 if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE))
 {
 if (avio_open(&outFormatCtx->pb, wavFilePath.toRawUTF8(), AVIO_FLAG_WRITE) < 0)
 {
 DBG("failed to open output file");
 return false;
 }
 }

 if (avformat_write_header(outFormatCtx, nullptr) < 0)
 {
 DBG("failed to write header to output file");
 return false;
 }

 int64_t total_samples = 0;

 while (av_read_frame(formatCtx, packet) >= 0)
 {
 if (packet->stream_index == audioStreamIndex)
 {
 if (avcodec_send_packet(codecCtx, packet) < 0)
 {
 DBG("failed secnding packet to decoder");
 av_packet_unref(packet);
 continue;
 }
 while (avcodec_receive_frame(codecCtx, frame) == 0)
 {
 int ret = swr_convert_frame(swrCtx, resampledFrame, frame);
 if (ret < 0)
 {
 char errBuf[AV_ERROR_MAX_STRING_SIZE];
 av_strerror(ret, errBuf, sizeof(errBuf));
 DBG("Error resampling frame: " + std::string(errBuf));
 continue;
 }

 resampledFrame->pts = av_rescale_q(total_samples, (AVRational{ 1, outCodecCtx->sample_rate }), outCodecCtx->time_base);
 total_samples += resampledFrame->nb_samples;

 AVPacket outPacket;
 av_init_packet(&outPacket);
 if (avcodec_send_frame(outCodecCtx, resampledFrame) < 0)
 {
 DBG("error sending frame to decoder");
 continue;
 }
 while (avcodec_receive_packet(outCodecCtx, &outPacket) == 0)
 {
 outPacket.stream_index = outStream->index;
 if (av_interleaved_write_frame(outFormatCtx, &outPacket) < 0)
 {
 av_packet_unref(&outPacket);
 DBG("error writing packet to output file");
 return false;
 }
 av_packet_unref(&outPacket);
 }
 }
 }
 av_packet_unref(packet);
 }

 /// trailer and cleanup
 av_write_trailer(outFormatCtx);

 avcodec_close(outCodecCtx);
 avcodec_close(codecCtx);
 avformat_close_input(&formatCtx);
 av_packet_free(&packet);
 av_frame_free(&frame);
 av_frame_free(&resampledFrame);
 swr_free(&swrCtx);
 if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE)) avio_closep(&outFormatCtx->pb);
 avformat_free_context(outFormatCtx);



Ive tried some debugging to see if the the values of either of the frames were unexpected or to see if the SwrContext might be unsual but did not manage anything. The thing I dont understand is the distinction that would cause this to fail for the right but not for when Im just doing the left.


-
C++ FFmpeg encode stream to mp4 wrong fps and kbs
22 mars 2024, par elmomoJackyi'm new to FFmpeg, i'm trying to learn how to encode images to an mp4 using a stream.
But even tough i can generate a playable file, my file is "broken", it does does past 1sec, and if i check it's data with ffmpeg i can see that it's duration is accordly wrong with the kb/s fps value




Duration : 00:00:00.01 .... 2635232 kb/s, 15463.09 fps.




ffmpeg -i 25_5.mp4 -f ffmetadata 25_5.txt


Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '25_5.mp4':
 Metadata:
 major_brand : isom
 minor_version : 512
 compatible_brands: isomiso2mp41
 title : Your Title Here
 encoder : Lavf60.16.100
 comment : Your Comment Here
 copyright : Copyright Information
 Duration: 00:00:00.01, start: 0.000000, bitrate: 2557680 kb/s
 Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 2635232 kb/s, 15463.09 fps, 15360 tbr, 15360 tbn, 30 tbc (default)
 Metadata:
 handler_name : VideoHandler
 vendor_id : [0][0][0][0]
File '25_5.txt' already exists. Overwrite? [y/N] y
Output #0, ffmetadata, to '25_5.txt':
 Metadata:
 major_brand : isom
 minor_version : 512
 compatible_brands: isomiso2mp41
 title : Your Title Here
 copyright : Copyright Information
 comment : Your Comment Here
 encoder : Lavf58.76.100



Here is my cpp and header code (using visual studio and vcpkg install ffmpeg)
file ffmpeg_example.cpp



#include "ffmpeg_example.h"

#include 
#include 
#include 
#include <iostream>
#include <map>

extern "C" {
#include <libavcodec></libavcodec>avcodec.h>
#include <libavformat></libavformat>avformat.h>
#include <libavutil></libavutil>imgutils.h>
#include <libavutil></libavutil>opt.h>
#include <libswscale></libswscale>swscale.h>

}

#define COMMON_AV_FRAME_FORMAT AV_PIX_FMT_YUV420P 

ffmpeg_example::ffmpeg_example()
{

}

ffmpeg_example::~ffmpeg_example()
{

}

void ffmpeg_example::set_codec_params(AVFormatContext*& fctx, AVCodecContext*& codec_ctx, double width, double height, int fps, int bitrate) {
 std::cout << "encoding video for width:" << width << ", height:" << height << ", fps:" << fps << ", bitrate:" << bitrate << std::endl;
 codec_ctx->codec_id = fctx->oformat->video_codec;
 codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
 codec_ctx->width = width;
 codec_ctx->height = height;
 codec_ctx->gop_size = 12;
 codec_ctx->pix_fmt = COMMON_AV_FRAME_FORMAT;
 codec_ctx->framerate = AVRational{ fps, 1 };
 codec_ctx->time_base = AVRational{ 1, fps };
 if (bitrate) codec_ctx->bit_rate = bitrate;
 if (fctx->oformat->flags & AVFMT_GLOBALHEADER) {
 codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 }
}

AVStream* ffmpeg_example::create_stream(AVFormatContext*& fctx, AVCodecContext*& codec_ctx) {
 AVStream* stream = avformat_new_stream(fctx, nullptr);
 avcodec_parameters_from_context(stream->codecpar, codec_ctx);
 stream->time_base = codec_ctx->time_base;
 //stream->r_frame_rate = codec_ctx->framerate;
 //stream->avg_frame_rate = stream->r_frame_rate;
 return stream;
}

AVFrame* ffmpeg_example::create_frame(int width, int height) {
 AVFrame* frame = av_frame_alloc();
 frame->format = COMMON_AV_FRAME_FORMAT;
 frame->width = width;
 frame->height = height;
 av_frame_get_buffer(frame, 0);
 return frame;
}

void ffmpeg_example::fill_fake_yuv_image(AVFrame* frame, int frame_index, int width, int height) {
 /* Ensure the data buffers are writable */
 av_frame_make_writable(frame);

 // This is where you could load actual image data into the frame.
 // For demonstration, we fill the frame with a color.
 // Y
 for (int y = 0; y < height; y++) {
 for (int x = 0; x < width; x++) {
 frame->data[0][y * frame->linesize[0] + x] = x + y + frame_index * 3;
 }
 }

 // Cb and Cr
 for (int y = 0; y < height / 2; y++) {
 for (int x = 0; x < width / 2; x++) {
 frame->data[1][y * frame->linesize[1] + x] = 128 + y + frame_index * 2;
 frame->data[2][y * frame->linesize[2] + x] = 64 + x + frame_index * 5;
 }
 }
}

int ffmpeg_example::initFfmpegcontext()
{
 int ret;


 // Initialize the AVFormatContext
 if (avformat_alloc_output_context2(&output_format_context, nullptr, _ouput_format, nullptr) < 0 || !output_format_context) {
 std::cout << "Could not allocat output context." << std::endl;
 return -1;
 }


 // Find the encoder
 encoder = avcodec_find_encoder(output_format_context->oformat->video_codec);
 if (!encoder) {
 std::cout << "Could not find encoder." << std::endl;
 return -1;
 }

 // Create a new codec context
 codec_context = avcodec_alloc_context3(encoder);
 if (!codec_context) {
 std::cout << "Could not allocate codec context." << std::endl;
 return -1;
 }

 // Set codec parameters
 set_codec_params(output_format_context, codec_context, 1920, 1080, video_fps, 0);

 // Open the codec
 ret = avcodec_open2(codec_context, encoder, nullptr);
 if (ret < 0) {
 std::cout << "Could not open encoder with context." << std::endl;
 return -1;
 }

 // Create a new video stream
 video_stream = create_stream(output_format_context, codec_context);
 if (!video_stream) {
 std::cout << "Could not create stream." << std::endl;
 return -1;
 }

 // Initialize the IO context
 if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
 std::cout << "Init IO, AVFMT_NOFILE not detected." << std::endl;
 if (avio_open(&output_format_context->pb, output, AVIO_FLAG_WRITE) < 0) {
 std::cout << "Could not open output file." << std::endl;
 return -1;
 }
 }

 // Write the file header
 ret = avformat_write_header(output_format_context, nullptr);
 if (ret < 0) {
 std::cout << "Could not write file header." << std::endl;
 return -1;
 }

 // Create a new frame
 frame = create_frame(codec_context->width, codec_context->height);
 if (!frame) {
 std::cout << "Could not create frame." << std::endl;
 return -1;
 }

 // Create a new packet
 pkt = av_packet_alloc();
 if (!pkt) {
 std::cout << "Could not allocate packet." << std::endl;
 return -1;
 }
 return 0;
}


void ffmpeg_example::set_metadata() {
 // Ensure the format context exists
 if (!output_format_context) return;
 std::cout << "Setting metadata." << std::endl;

 // Create or get the existing metadata dictionary
 AVDictionary** metadata = &output_format_context->metadata;

 // Set various metadata fields
 av_dict_set(metadata, "title", "Your Title Here", 0);
 av_dict_set(metadata, "author", "Author Name", 0);
 av_dict_set(metadata, "copyright", "Copyright Information", 0);
 av_dict_set(metadata, "comment", "Your Comment Here", 0);
 av_dict_set(metadata, "rating", "5", 0); // Assuming rating is a simple numeric value

 // Note: The last parameter of av_dict_set is a flag; 0 means the entry will be added to the dictionary
 // if it doesn't exist, or the existing entry will be updated if it does exist.
}

int ffmpeg_example::start()
{
 int ret;
 if (initFfmpegcontext() < 0) {
 std::cout << "quitting" << std::endl;
 return -1;
 }

 set_metadata();
 std::cout << "filling stream with frames data." << std::endl;
 // Write frames
 for (int i = 0; i < video_fps * 4; i++) { // 5 seconds at video_fps fps
 frame->pts = i;
 fill_fake_yuv_image(frame, i, codec_context->width, codec_context->height);

 // Encode the image
 ret = avcodec_send_frame(codec_context, frame);
 while (ret >= 0) {
 ret = avcodec_receive_packet(codec_context, pkt);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
 break;
 }
 pkt->stream_index = video_stream->index;
 av_interleaved_write_frame(output_format_context, pkt);
 av_packet_unref(pkt);
 }
 }

 std::cout << "closing." << std::endl;
 // Send a null frame to the encoder to flush it
 avcodec_send_frame(codec_context, NULL);
 while (ret >= 0) {
 ret = avcodec_receive_packet(codec_context, pkt);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
 break;
 }
 pkt->stream_index = video_stream->index;
 av_interleaved_write_frame(output_format_context, pkt);
 av_packet_unref(pkt);
 }

 // Write the file trailer
 av_write_trailer(output_format_context);

 cleanup();
 std::cout << "done." << std::endl;

 return 0;
}

void ffmpeg_example::cleanup() {
 // Clean up
 avcodec_free_context(&codec_context);
 av_frame_free(&frame);
 av_packet_free(&pkt);
 avio_closep(&output_format_context->pb);
 avformat_free_context(output_format_context);
}
</map></iostream>


Header file :


#pragma once

class AVFormatContext;
class AVCodecContext;
class AVStream;
class AVCodec;
class AVFrame;
class AVPacket;
class AVOutputFormat;

class ffmpeg_example {
private:
 const AVCodec* encoder = nullptr;
 AVFormatContext* output_format_context = nullptr;
 AVCodecContext* codec_context = nullptr;
 AVStream* video_stream = nullptr;
 AVFrame* frame = nullptr;
 AVPacket* pkt = nullptr;

 const char* output = "output.mp4";
 const char* _ouput_format = "mp4";

 int video_fps = 30;
public:

 ffmpeg_example();
 virtual ~ffmpeg_example();

 int start();
private:
 int initFfmpegcontext();
 AVFrame* create_frame(int width, int height);
 void fill_fake_yuv_image(AVFrame* frame, int frame_index, int width, int height);
 void set_codec_params(AVFormatContext*& fctx, AVCodecContext*& codec_ctx, double width, double height, int fps, int bitrate);
 AVStream* create_stream(AVFormatContext*& fctx, AVCodecContext*& codec_ctx);

 void cleanup();
 void set_metadata();
};



You just have to call the start() function to make it work.


I understand that the problem come surely from a flag disabling my fps setting, or it's an incorrect param while generating the header, but i can't find which one.
I searched other similar examples (ffmpeg example like encode_video.c or stackoverflow post : video-too-fast, speed-encoding-problem, ffmpeg-create-mp4 )
But whatever change i make i cannot make it work (and chatgpt is as lost as me).


— edit


The only way i find to impact the fps of the ouputed video is to invers
codec_ctx->framerate = AVRational{ 1, fps };
but even with that, my video is marked 30sec (should be 5) and doesn't past 1sec.
I'M LOST, i can count the number of packet -> 150



ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 output.mp4
150




Each frame has the correct pts so that it know in which order to play, my stream has the same avg_frame_rate as my codec framerate.


I don't know what i do wrong