
Recherche avancée
Médias (3)
-
GetID3 - Bloc informations de fichiers
9 avril 2013, par
Mis à jour : Mai 2013
Langue : français
Type : Image
-
GetID3 - Boutons supplémentaires
9 avril 2013, par
Mis à jour : Avril 2013
Langue : français
Type : Image
-
Collections - Formulaire de création rapide
19 février 2013, par
Mis à jour : Février 2013
Langue : français
Type : Image
Autres articles (102)
-
Multilang : améliorer l’interface pour les blocs multilingues
18 février 2011, parMultilang est un plugin supplémentaire qui n’est pas activé par défaut lors de l’initialisation de MediaSPIP.
Après son activation, une préconfiguration est mise en place automatiquement par MediaSPIP init permettant à la nouvelle fonctionnalité d’être automatiquement opérationnelle. Il n’est donc pas obligatoire de passer par une étape de configuration pour cela. -
Des sites réalisés avec MediaSPIP
2 mai 2011, parCette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page. -
ANNEXE : Les plugins utilisés spécifiquement pour la ferme
5 mars 2010, parLe site central/maître de la ferme a besoin d’utiliser plusieurs plugins supplémentaires vis à vis des canaux pour son bon fonctionnement. le plugin Gestion de la mutualisation ; le plugin inscription3 pour gérer les inscriptions et les demandes de création d’instance de mutualisation dès l’inscription des utilisateurs ; le plugin verifier qui fournit une API de vérification des champs (utilisé par inscription3) ; le plugin champs extras v2 nécessité par inscription3 (...)
Sur d’autres sites (9030)
-
Issues with Video Recording Duration and Smooth Playback when Using v4l2 framework to MP4 (FFmpeg)
9 décembre 2024, par ReenaI'm trying to record a video from a USB device with v4l2 framework and save it in MP4 format using FFmpeg. My sample code successfully captures and saves the video, but I'm running into some issues :


The recorded video duration is shorter than expected. For instance :


When recording a 1-minute video at 1280x720, the output file only has 58 or 59 seconds. For 1920x1080, the duration is even more off — only about 28 or 30 seconds, instead of the expected 1 minute. Additionally, the video is not smooth. There are noticeable drops in frames and playback inconsistencies.


My setup :


Using a USB device with v4l2 framework Saving the video in MP4 format Tested with different resolutions (1280x720, 1920x1080) I've attached my sample code below. Could someone help me figure out why I'm experiencing these issues with video duration and smooth playback ?


#include 
#include 
#include 
#include 
#include <sys></sys>ioctl.h>
#include <sys></sys>mman.h>
#include <linux></linux>videodev2.h>
#include <libavformat></libavformat>avformat.h>
#include <libavcodec></libavcodec>avcodec.h>
#include <libavutil></libavutil>imgutils.h>
#include <libavutil></libavutil>opt.h>
#include <libswscale></libswscale>swscale.h>
#include 
#include <sys></sys>time.h>
#include 

#define WIDTH 1280
#define HEIGHT 720
#define FPS 30
#define DURATION 10 // Recording duration in seconds
#define BUFFER_COUNT 4 // Number of buffers

struct buffer {
 void *start;
 size_t length;
};

struct buffer *buffers;

void open_device(int *fd, const char *device) {
 *fd = open(device, O_RDWR | O_NONBLOCK);
 if (*fd < 0) {
 perror("Cannot open video device");
 exit(1);
 }
}

void init_mmap(int fd) {
 struct v4l2_requestbuffers req;
 memset(&req, 0, sizeof(req));
 req.count = BUFFER_COUNT;
 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 req.memory = V4L2_MEMORY_MMAP;

 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
 perror("Requesting buffer");
 exit(1);
 }

 buffers = calloc(req.count, sizeof(*buffers));
 for (size_t i = 0; i < req.count; ++i) {
 struct v4l2_buffer buf;
 memset(&buf, 0, sizeof(buf));
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buf.memory = V4L2_MEMORY_MMAP;
 buf.index = i;

 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
 perror("Querying buffer");
 exit(1);
 }

 buffers[i].length = buf.length;
 buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);

 if (MAP_FAILED == buffers[i].start) {
 perror("mmap");
 exit(1);
 }
 }
}

void start_capturing(int fd) {
 for (size_t i = 0; i < BUFFER_COUNT; ++i) {
 struct v4l2_buffer buf;
 memset(&buf, 0, sizeof(buf));
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buf.memory = V4L2_MEMORY_MMAP;
 buf.index = i;

 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
 perror("Queue buffer");
 exit(1);
 }
 }

 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
 perror("Start capture");
 exit(1);
 }
}

void stop_capturing(int fd) {
 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

 if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) {
 perror("Stop capture");
 exit(1);
 }

 printf("Video capture stopped.\n");
}

void unmap_buffers() {
 for (size_t i = 0; i < BUFFER_COUNT; ++i) {
 if (munmap(buffers[i].start, buffers[i].length) < 0) {
 perror("munmap");
 exit(1);
 }
 }

 free(buffers);
}

void initialize_ffmpeg(AVFormatContext **fmt_ctx, AVCodecContext **codec_ctx, AVStream **video_stream, const char *filename) {
 av_register_all();

 AVOutputFormat *fmt = av_guess_format(NULL, filename, NULL);
 if (!fmt) {
 fprintf(stderr, "Could not determine output format\n");
 exit(1);
 }

 if (avformat_alloc_output_context2(fmt_ctx, fmt, NULL, filename) < 0) {
 fprintf(stderr, "Could not allocate format context\n");
 exit(1);
 }

 AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
 if (!codec) {
 fprintf(stderr, "Codec not found\n");
 exit(1);
 }

 *video_stream = avformat_new_stream(*fmt_ctx, NULL);
 if (!*video_stream) {
 fprintf(stderr, "Could not create stream\n");
 exit(1);
 }

 *codec_ctx = avcodec_alloc_context3(codec);
 if (!*codec_ctx) {
 fprintf(stderr, "Could not allocate codec context\n");
 exit(1);
 }

 (*codec_ctx)->codec_type = AVMEDIA_TYPE_VIDEO;
 (*codec_ctx)->width = WIDTH;
 (*codec_ctx)->height = HEIGHT;
 (*codec_ctx)->time_base = (AVRational){1, FPS};
 (*codec_ctx)->framerate = (AVRational){FPS, 1};
 (*codec_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;
 (*codec_ctx)->gop_size = 10;
 (*codec_ctx)->max_b_frames = 1;

 av_opt_set(*codec_ctx, "preset", "fast", 0);
 av_opt_set_int(*codec_ctx, "crf", 23, 0);

 (*video_stream)->time_base = (*codec_ctx)->time_base;
 (*video_stream)->codecpar->codec_id = fmt->video_codec;
 (*video_stream)->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
 (*video_stream)->codecpar->width = (*codec_ctx)->width;
 (*video_stream)->codecpar->height = (*codec_ctx)->height;
 (*video_stream)->codecpar->format = (*codec_ctx)->pix_fmt;

 if ((*fmt_ctx)->oformat->flags & AVFMT_GLOBALHEADER) {
 (*codec_ctx)->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 }

 if (avcodec_open2(*codec_ctx, codec, NULL) < 0) {
 fprintf(stderr, "Could not open codec\n");
 exit(1);
 }

 if (avcodec_parameters_from_context((*video_stream)->codecpar, *codec_ctx) < 0) {
 fprintf(stderr, "Could not copy codec parameters\n");
 exit(1);
 }

 if (!(fmt->flags & AVFMT_NOFILE)) {
 if (avio_open(&(*fmt_ctx)->pb, filename, AVIO_FLAG_WRITE) < 0) {
 fprintf(stderr, "Could not open output file\n");
 exit(1);
 }
 }

 if (avformat_write_header(*fmt_ctx, NULL) < 0) {
 fprintf(stderr, "Could not write header\n");
 exit(1);
 }
}

void capture_and_encode(int fd, AVFormatContext *fmt_ctx, AVCodecContext *codec_ctx, struct SwsContext *sws_ctx, AVStream *video_stream, int duration) {
 struct v4l2_buffer buffer;
 AVFrame *frame = av_frame_alloc();
 AVPacket packet;
 av_init_packet(&packet);

 frame->format = codec_ctx->pix_fmt;
 frame->width = codec_ctx->width;
 frame->height = codec_ctx->height;
 av_image_alloc(frame->data, frame->linesize, codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, 32);

 struct timespec start_time;
 clock_gettime(CLOCK_MONOTONIC, &start_time);
 double elapsed_time = 0;
 int64_t pts_counter = 0;
 int frame_count = 0;

 while (elapsed_time < duration) {
 fd_set fds;
 struct timeval tv;
 int r;

 FD_ZERO(&fds);
 FD_SET(fd, &fds);

 tv.tv_sec = 2;
 tv.tv_usec = 0;

 r = select(fd + 1, &fds, NULL, NULL, &tv);
 if (r == -1) {
 perror("select");
 exit(1);
 }

 if (r == 0) {
 fprintf(stderr, "select timeout\n");
 exit(1);
 }

 memset(&buffer, 0, sizeof(buffer));
 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buffer.memory = V4L2_MEMORY_MMAP;

 if (ioctl(fd, VIDIOC_DQBUF, &buffer) < 0) {
 if (errno == EAGAIN) continue;
 perror("Could not dequeue buffer");
 exit(1);
 }

 uint8_t *src_slices[1] = {buffers[buffer.index].start};
 int src_stride[1] = {WIDTH * 2}; // UYVY is 2 bytes per pixel

 sws_scale(sws_ctx, src_slices, src_stride, 0, HEIGHT, frame->data, frame->linesize);

 frame->pts = pts_counter;
 pts_counter += av_rescale_q(1, (AVRational){1, FPS}, codec_ctx->time_base);

 if (avcodec_send_frame(codec_ctx, frame) < 0) {
 fprintf(stderr, "Error sending frame\n");
 exit(1);
 }

 while (avcodec_receive_packet(codec_ctx, &packet) == 0) {
 av_packet_rescale_ts(&packet, codec_ctx->time_base, video_stream->time_base);
 packet.stream_index = video_stream->index;

 if (av_interleaved_write_frame(fmt_ctx, &packet) < 0) {
 fprintf(stderr, "Error writing frame\n");
 exit(1);
 }

 av_packet_unref(&packet);
 }
 printf("Processed frame %d\n", frame_count);

 if (ioctl(fd, VIDIOC_QBUF, &buffer) < 0) {
 perror("Could not requeue buffer");
 exit(1);
 }
 frame_count++;
 struct timespec current_time;
 clock_gettime(CLOCK_MONOTONIC, &current_time);
 elapsed_time = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_nsec - start_time.tv_nsec) / 1e9;
 printf("Elapsed time: %f seconds\n", elapsed_time);
 }

 av_freep(&frame->data[0]);
 av_frame_free(&frame);
 printf("Total frames processed: %d\n", frame_count);
}

int main(int argc, char *argv[]) {
 if (argc != 2) {
 fprintf(stderr, "Usage: %s <output file="file">\n", argv[0]);
 exit(1);
 }

 const char *output_file = argv[1];
 int fd;
 open_device(&fd, "/dev/video2");

 struct v4l2_format fmt;
 memset(&fmt, 0, sizeof(fmt));
 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 fmt.fmt.pix.width = WIDTH;
 fmt.fmt.pix.height = HEIGHT;
 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
 fmt.fmt.pix.field = V4L2_FIELD_NONE;

 if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
 perror("Setting pixel format");
 exit(1);
 }

 if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) {
 fprintf(stderr, "Device does not support UYVY format\n");
 exit(1);
 }

 init_mmap(fd);
 start_capturing(fd);

 AVFormatContext *fmt_ctx = NULL;
 AVCodecContext *codec_ctx = NULL;
 AVStream *video_stream = NULL;

 initialize_ffmpeg(&fmt_ctx, &codec_ctx, &video_stream, output_file);

 struct SwsContext *sws_ctx = sws_getContext(WIDTH, HEIGHT, AV_PIX_FMT_UYVY422,
 WIDTH, HEIGHT, AV_PIX_FMT_YUV420P,
 SWS_BICUBIC, NULL, NULL, NULL);

 if (!sws_ctx) {
 fprintf(stderr, "Could not initialize SwsContext\n");
 exit(1);
 }

 capture_and_encode(fd, fmt_ctx, codec_ctx, sws_ctx, video_stream, DURATION);

 sws_freeContext(sws_ctx);
 av_write_trailer(fmt_ctx);
 avcodec_free_context(&codec_ctx);
 avformat_free_context(fmt_ctx);
 stop_capturing(fd);
 unmap_buffers();
 close(fd);

 return 0;
}
</output>


-
Issues with Video Recording Duration and Smooth Playback when Using v4l2 to MP4 (FFmpeg)
9 décembre 2024, par ReenaI'm trying to record a video from a USB device with v4l2 framework and save it in MP4 format using FFmpeg. My sample code successfully captures and saves the video, but I'm running into some issues :


The recorded video duration is shorter than expected. For instance :


When recording a 1-minute video at 1280x720, the output file only has 58 or 59 seconds.
For 1920x1080, the duration is even more off — only about 28 or 30 seconds, instead of the expected 1 minute.
Additionally, the video is not smooth. There are noticeable drops in frames and playback inconsistencies.


My setup :


Using a USB device with v4l2 framework
Saving the video in MP4 format
Tested with different resolutions (1280x720, 1920x1080)
I've attached my sample code below. Could someone help me figure out why I'm experiencing these issues with video duration and smooth playback ?


Any advice, fixes, or suggestions would be greatly appreciated !


#include 
#include 
#include 
#include 
#include <sys></sys>ioctl.h>
#include <sys></sys>mman.h>
#include <linux></linux>videodev2.h>
#include <libavformat></libavformat>avformat.h>
#include <libavcodec></libavcodec>avcodec.h>
#include <libavutil></libavutil>imgutils.h>
#include <libavutil></libavutil>opt.h>
#include <libswscale></libswscale>swscale.h>
#include 
#include <sys></sys>time.h>
#include 

#define WIDTH 1280
#define HEIGHT 720
#define FPS 30
#define DURATION 10 // Recording duration in seconds
#define BUFFER_COUNT 4 // Number of buffers

struct buffer {
 void *start;
 size_t length;
};

struct buffer *buffers;

void open_device(int *fd, const char *device) {
 *fd = open(device, O_RDWR | O_NONBLOCK);
 if (*fd < 0) {
 perror("Cannot open video device");
 exit(1);
 }
}

void init_mmap(int fd) {
 struct v4l2_requestbuffers req;
 memset(&req, 0, sizeof(req));
 req.count = BUFFER_COUNT;
 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 req.memory = V4L2_MEMORY_MMAP;

 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
 perror("Requesting buffer");
 exit(1);
 }

 buffers = calloc(req.count, sizeof(*buffers));
 for (size_t i = 0; i < req.count; ++i) {
 struct v4l2_buffer buf;
 memset(&buf, 0, sizeof(buf));
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buf.memory = V4L2_MEMORY_MMAP;
 buf.index = i;

 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
 perror("Querying buffer");
 exit(1);
 }

 buffers[i].length = buf.length;
 buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);

 if (MAP_FAILED == buffers[i].start) {
 perror("mmap");
 exit(1);
 }
 }
}

void start_capturing(int fd) {
 for (size_t i = 0; i < BUFFER_COUNT; ++i) {
 struct v4l2_buffer buf;
 memset(&buf, 0, sizeof(buf));
 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buf.memory = V4L2_MEMORY_MMAP;
 buf.index = i;

 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
 perror("Queue buffer");
 exit(1);
 }
 }

 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
 perror("Start capture");
 exit(1);
 }
}

void stop_capturing(int fd) {
 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

 if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) {
 perror("Stop capture");
 exit(1);
 }

 printf("Video capture stopped.\n");
}

void unmap_buffers() {
 for (size_t i = 0; i < BUFFER_COUNT; ++i) {
 if (munmap(buffers[i].start, buffers[i].length) < 0) {
 perror("munmap");
 exit(1);
 }
 }

 free(buffers);
}

void initialize_ffmpeg(AVFormatContext **fmt_ctx, AVCodecContext **codec_ctx, AVStream **video_stream, const char *filename) {
 av_register_all();

 AVOutputFormat *fmt = av_guess_format(NULL, filename, NULL);
 if (!fmt) {
 fprintf(stderr, "Could not determine output format\n");
 exit(1);
 }

 if (avformat_alloc_output_context2(fmt_ctx, fmt, NULL, filename) < 0) {
 fprintf(stderr, "Could not allocate format context\n");
 exit(1);
 }

 AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
 if (!codec) {
 fprintf(stderr, "Codec not found\n");
 exit(1);
 }

 *video_stream = avformat_new_stream(*fmt_ctx, NULL);
 if (!*video_stream) {
 fprintf(stderr, "Could not create stream\n");
 exit(1);
 }

 *codec_ctx = avcodec_alloc_context3(codec);
 if (!*codec_ctx) {
 fprintf(stderr, "Could not allocate codec context\n");
 exit(1);
 }

 (*codec_ctx)->codec_type = AVMEDIA_TYPE_VIDEO;
 (*codec_ctx)->width = WIDTH;
 (*codec_ctx)->height = HEIGHT;
 (*codec_ctx)->time_base = (AVRational){1, FPS};
 (*codec_ctx)->framerate = (AVRational){FPS, 1};
 (*codec_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;
 (*codec_ctx)->gop_size = 10;
 (*codec_ctx)->max_b_frames = 1;

 av_opt_set(*codec_ctx, "preset", "fast", 0);
 av_opt_set_int(*codec_ctx, "crf", 23, 0);

 (*video_stream)->time_base = (*codec_ctx)->time_base;
 (*video_stream)->codecpar->codec_id = fmt->video_codec;
 (*video_stream)->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
 (*video_stream)->codecpar->width = (*codec_ctx)->width;
 (*video_stream)->codecpar->height = (*codec_ctx)->height;
 (*video_stream)->codecpar->format = (*codec_ctx)->pix_fmt;

 if ((*fmt_ctx)->oformat->flags & AVFMT_GLOBALHEADER) {
 (*codec_ctx)->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 }

 if (avcodec_open2(*codec_ctx, codec, NULL) < 0) {
 fprintf(stderr, "Could not open codec\n");
 exit(1);
 }

 if (avcodec_parameters_from_context((*video_stream)->codecpar, *codec_ctx) < 0) {
 fprintf(stderr, "Could not copy codec parameters\n");
 exit(1);
 }

 if (!(fmt->flags & AVFMT_NOFILE)) {
 if (avio_open(&(*fmt_ctx)->pb, filename, AVIO_FLAG_WRITE) < 0) {
 fprintf(stderr, "Could not open output file\n");
 exit(1);
 }
 }

 if (avformat_write_header(*fmt_ctx, NULL) < 0) {
 fprintf(stderr, "Could not write header\n");
 exit(1);
 }
}

void capture_and_encode(int fd, AVFormatContext *fmt_ctx, AVCodecContext *codec_ctx, struct SwsContext *sws_ctx, AVStream *video_stream, int duration) {
 struct v4l2_buffer buffer;
 AVFrame *frame = av_frame_alloc();
 AVPacket packet;
 av_init_packet(&packet);

 frame->format = codec_ctx->pix_fmt;
 frame->width = codec_ctx->width;
 frame->height = codec_ctx->height;
 av_image_alloc(frame->data, frame->linesize, codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, 32);

 struct timespec start_time;
 clock_gettime(CLOCK_MONOTONIC, &start_time);
 double elapsed_time = 0;
 int64_t pts_counter = 0;
 int frame_count = 0;

 while (elapsed_time < duration) {
 fd_set fds;
 struct timeval tv;
 int r;

 FD_ZERO(&fds);
 FD_SET(fd, &fds);

 tv.tv_sec = 2;
 tv.tv_usec = 0;

 r = select(fd + 1, &fds, NULL, NULL, &tv);
 if (r == -1) {
 perror("select");
 exit(1);
 }

 if (r == 0) {
 fprintf(stderr, "select timeout\n");
 exit(1);
 }

 memset(&buffer, 0, sizeof(buffer));
 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 buffer.memory = V4L2_MEMORY_MMAP;

 if (ioctl(fd, VIDIOC_DQBUF, &buffer) < 0) {
 if (errno == EAGAIN) continue;
 perror("Could not dequeue buffer");
 exit(1);
 }

 uint8_t *src_slices[1] = {buffers[buffer.index].start};
 int src_stride[1] = {WIDTH * 2}; // UYVY is 2 bytes per pixel

 sws_scale(sws_ctx, src_slices, src_stride, 0, HEIGHT, frame->data, frame->linesize);

 frame->pts = pts_counter;
 pts_counter += av_rescale_q(1, (AVRational){1, FPS}, codec_ctx->time_base);

 if (avcodec_send_frame(codec_ctx, frame) < 0) {
 fprintf(stderr, "Error sending frame\n");
 exit(1);
 }

 while (avcodec_receive_packet(codec_ctx, &packet) == 0) {
 av_packet_rescale_ts(&packet, codec_ctx->time_base, video_stream->time_base);
 packet.stream_index = video_stream->index;

 if (av_interleaved_write_frame(fmt_ctx, &packet) < 0) {
 fprintf(stderr, "Error writing frame\n");
 exit(1);
 }

 av_packet_unref(&packet);
 }
 printf("Processed frame %d\n", frame_count);

 if (ioctl(fd, VIDIOC_QBUF, &buffer) < 0) {
 perror("Could not requeue buffer");
 exit(1);
 }
 frame_count++;
 struct timespec current_time;
 clock_gettime(CLOCK_MONOTONIC, &current_time);
 elapsed_time = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_nsec - start_time.tv_nsec) / 1e9;
 printf("Elapsed time: %f seconds\n", elapsed_time);
 }

 av_freep(&frame->data[0]);
 av_frame_free(&frame);
 printf("Total frames processed: %d\n", frame_count);
}

int main(int argc, char *argv[]) {
 if (argc != 2) {
 fprintf(stderr, "Usage: %s <output file="file">\n", argv[0]);
 exit(1);
 }

 const char *output_file = argv[1];
 int fd;
 open_device(&fd, "/dev/video2");

 struct v4l2_format fmt;
 memset(&fmt, 0, sizeof(fmt));
 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 fmt.fmt.pix.width = WIDTH;
 fmt.fmt.pix.height = HEIGHT;
 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
 fmt.fmt.pix.field = V4L2_FIELD_NONE;

 if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
 perror("Setting pixel format");
 exit(1);
 }

 if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) {
 fprintf(stderr, "Device does not support UYVY format\n");
 exit(1);
 }

 init_mmap(fd);
 start_capturing(fd);

 AVFormatContext *fmt_ctx = NULL;
 AVCodecContext *codec_ctx = NULL;
 AVStream *video_stream = NULL;

 initialize_ffmpeg(&fmt_ctx, &codec_ctx, &video_stream, output_file);

 struct SwsContext *sws_ctx = sws_getContext(WIDTH, HEIGHT, AV_PIX_FMT_UYVY422,
 WIDTH, HEIGHT, AV_PIX_FMT_YUV420P,
 SWS_BICUBIC, NULL, NULL, NULL);

 if (!sws_ctx) {
 fprintf(stderr, "Could not initialize SwsContext\n");
 exit(1);
 }

 capture_and_encode(fd, fmt_ctx, codec_ctx, sws_ctx, video_stream, DURATION);

 sws_freeContext(sws_ctx);
 av_write_trailer(fmt_ctx);
 avcodec_free_context(&codec_ctx);
 avformat_free_context(fmt_ctx);
 stop_capturing(fd);
 unmap_buffers();
 close(fd);

 return 0;
}
</output>


Thank you !


-
C++ ffmpeg - export to wav error : Invalid PCM packet, data has size 2 but at least a size of 4 was expected
9 septembre 2024, par Chris PC++ code :


AudioSegment AudioSegment::from_file(const std::string& file_path, const std::string& format, const std::string& codec,
 const std::map& parameters, int start_second, int duration) {

 avformat_network_init();
 av_log_set_level(AV_LOG_ERROR); // Adjust logging level as needed

 AVFormatContext* format_ctx = nullptr;
 if (avformat_open_input(&format_ctx, file_path.c_str(), nullptr, nullptr) != 0) {
 std::cerr << "Error: Could not open audio file." << std::endl;
 return AudioSegment(); // Return an empty AudioSegment on failure
 }

 if (avformat_find_stream_info(format_ctx, nullptr) < 0) {
 std::cerr << "Error: Could not find stream information." << std::endl;
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 int audio_stream_index = -1;
 for (unsigned int i = 0; i < format_ctx->nb_streams; i++) {
 if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
 audio_stream_index = i;
 break;
 }
 }

 if (audio_stream_index == -1) {
 std::cerr << "Error: Could not find audio stream." << std::endl;
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 AVCodecParameters* codec_par = format_ctx->streams[audio_stream_index]->codecpar;
 const AVCodec* my_codec = avcodec_find_decoder(codec_par->codec_id);
 AVCodecContext* codec_ctx = avcodec_alloc_context3(my_codec);

 if (!codec_ctx) {
 std::cerr << "Error: Could not allocate codec context." << std::endl;
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 if (avcodec_parameters_to_context(codec_ctx, codec_par) < 0) {
 std::cerr << "Error: Could not initialize codec context." << std::endl;
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 if (avcodec_open2(codec_ctx, my_codec, nullptr) < 0) {
 std::cerr << "Error: Could not open codec." << std::endl;
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 SwrContext* swr_ctx = swr_alloc();
 if (!swr_ctx) {
 std::cerr << "Error: Could not allocate SwrContext." << std::endl;
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }
 codec_ctx->sample_rate = 44100;
 // Set up resampling context to convert to S16 format with 2 bytes per sample
 av_opt_set_chlayout(swr_ctx, "in_chlayout", &codec_ctx->ch_layout, 0);
 av_opt_set_int(swr_ctx, "in_sample_rate", codec_ctx->sample_rate, 0);
 av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", codec_ctx->sample_fmt, 0);

 AVChannelLayout dst_ch_layout;
 av_channel_layout_copy(&dst_ch_layout, &codec_ctx->ch_layout);
 av_channel_layout_uninit(&dst_ch_layout);
 av_channel_layout_default(&dst_ch_layout, 2);

 av_opt_set_chlayout(swr_ctx, "out_chlayout", &dst_ch_layout, 0);
 av_opt_set_int(swr_ctx, "out_sample_rate", codec_ctx->sample_rate, 0); // Match input sample rate
 av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); // Force S16 format

 if (swr_init(swr_ctx) < 0) {
 std::cerr << "Error: Failed to initialize the resampling context" << std::endl;
 swr_free(&swr_ctx);
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 AVPacket packet;
 AVFrame* frame = av_frame_alloc();
 if (!frame) {
 std::cerr << "Error: Could not allocate frame." << std::endl;
 swr_free(&swr_ctx);
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);
 return AudioSegment();
 }

 std::vector<char> output;
 while (av_read_frame(format_ctx, &packet) >= 0) {
 if (packet.stream_index == audio_stream_index) {
 if (avcodec_send_packet(codec_ctx, &packet) == 0) {
 while (avcodec_receive_frame(codec_ctx, frame) == 0) {
 if (frame->pts != AV_NOPTS_VALUE) {
 frame->pts = av_rescale_q(frame->pts, codec_ctx->time_base, format_ctx->streams[audio_stream_index]->time_base);
 }

 uint8_t* output_buffer;
 int output_samples = av_rescale_rnd(
 swr_get_delay(swr_ctx, codec_ctx->sample_rate) + frame->nb_samples,
 codec_ctx->sample_rate, codec_ctx->sample_rate, AV_ROUND_UP);

 int output_buffer_size = av_samples_get_buffer_size(
 nullptr, 2, output_samples, AV_SAMPLE_FMT_S16, 1);

 output_buffer = (uint8_t*)av_malloc(output_buffer_size);

 if (output_buffer) {
 memset(output_buffer, 0, output_buffer_size); // Zero padding to avoid random noise
 int converted_samples = swr_convert(swr_ctx, &output_buffer, output_samples,
 (const uint8_t**)frame->extended_data, frame->nb_samples);

 if (converted_samples >= 0) {
 output.insert(output.end(), output_buffer, output_buffer + output_buffer_size);
 }
 else {
 std::cerr << "Error: Failed to convert audio samples." << std::endl;
 }
 // Make sure output_buffer is valid before freeing
 if (output_buffer != nullptr) {
 av_free(output_buffer);
 output_buffer = nullptr; // Prevent double-free
 }
 }
 else {
 std::cerr << "Error: Could not allocate output buffer." << std::endl;
 }
 }
 }
 else {
 std::cerr << "Error: Failed to send packet to codec context." << std::endl;
 }
 }
 av_packet_unref(&packet);
 }

 int frame_width = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * 2; // Use 2 bytes per sample and 2 channels

 std::map metadata = {
 {"sample_width", 2}, // S16 format has 2 bytes per sample
 {"frame_rate", codec_ctx->sample_rate}, // Use the input sample rate
 {"channels", 2}, // Assuming stereo output
 {"frame_width", frame_width}
 };

 av_frame_free(&frame);
 swr_free(&swr_ctx);
 avcodec_free_context(&codec_ctx);
 avformat_close_input(&format_ctx);

 return AudioSegment(static_cast<const>(output.data()), output.size(), metadata);
}

std::ofstream AudioSegment::export_segment_to_wav_file(const std::string& out_f) {
 std::cout << this->get_channels() << std::endl;
 av_log_set_level(AV_LOG_ERROR);
 AVCodecContext* codec_ctx = nullptr;
 AVFormatContext* format_ctx = nullptr;
 AVStream* stream = nullptr;
 AVFrame* frame = nullptr;
 AVPacket* pkt = nullptr;
 int ret;

 // Initialize format context for WAV
 if (avformat_alloc_output_context2(&format_ctx, nullptr, "wav", out_f.c_str()) < 0) {
 throw std::runtime_error("Could not allocate format context.");
 }

 // Find encoder for PCM
 const AVCodec* codec_ptr = avcodec_find_encoder(AV_CODEC_ID_PCM_S16LE);
 if (!codec_ptr) {
 throw std::runtime_error("PCM encoder not found.");
 }

 // Add stream
 stream = avformat_new_stream(format_ctx, codec_ptr);
 if (!stream) {
 throw std::runtime_error("Failed to create new stream.");
 }

 // Allocate codec context
 codec_ctx = avcodec_alloc_context3(codec_ptr);
 if (!codec_ctx) {
 throw std::runtime_error("Could not allocate audio codec context.");
 }

 // Set codec parameters for PCM
 codec_ctx->bit_rate = 128000; // Bitrate
 codec_ctx->sample_rate = this->get_frame_rate(); // Use correct sample rate
 codec_ctx->ch_layout.nb_channels = this->get_channels(); // Set the correct channel count

 // Set the channel layout: stereo or mono
 if (this->get_channels() == 2) {
 av_channel_layout_default(&codec_ctx->ch_layout, 2); // Stereo layout
 }
 else {
 av_channel_layout_default(&codec_ctx->ch_layout, 1); // Mono layout
 }

 codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16; // PCM 16-bit format

 // Open codec
 if (avcodec_open2(codec_ctx, codec_ptr, nullptr) < 0) {
 throw std::runtime_error("Could not open codec.");
 }

 // Set codec parameters to the stream
 if (avcodec_parameters_from_context(stream->codecpar, codec_ctx) < 0) {
 throw std::runtime_error("Could not initialize stream codec parameters.");
 }

 // Open output file
 std::ofstream out_file(out_f, std::ios::binary);
 if (!out_file) {
 throw std::runtime_error("Failed to open output file.");
 }

 if (!(format_ctx->oformat->flags & AVFMT_NOFILE)) {
 if (avio_open(&format_ctx->pb, out_f.c_str(), AVIO_FLAG_WRITE) < 0) {
 throw std::runtime_error("Could not open output file.");
 }
 }

 // Write file header
 if (avformat_write_header(format_ctx, nullptr) < 0) {
 throw std::runtime_error("Error occurred when writing file header.");
 }

 // Initialize packet
 pkt = av_packet_alloc();
 if (!pkt) {
 throw std::runtime_error("Could not allocate AVPacket.");
 }

 // Initialize frame
 frame = av_frame_alloc();
 if (!frame) {
 throw std::runtime_error("Could not allocate AVFrame.");
 }

 // Set the frame properties
 frame->format = codec_ctx->sample_fmt;
 frame->ch_layout = codec_ctx->ch_layout;

 // Number of audio samples available in the data buffer
 int total_samples = data_.size() / (av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * codec_ctx->ch_layout.nb_channels);
 int samples_read = 0;

 // Set the number of samples per frame dynamically based on the input data
 while (samples_read < total_samples) {
 // Determine how many samples to read in this iteration (don't exceed the total sample count)
 int num_samples = std::min(codec_ctx->frame_size, total_samples - samples_read);
 if (num_samples == 0) {
 num_samples = 1024;
 codec_ctx->frame_size = 1024;
 }
 // Ensure num_samples is not zero
 if (num_samples <= 0) {
 throw std::runtime_error("Invalid number of samples in frame.");
 }

 // Set the number of samples in the frame
 frame->nb_samples = num_samples;

 // Allocate the frame buffer based on the number of samples
 ret = av_frame_get_buffer(frame, 0);
 if (ret < 0) {
 std::cerr << "Error allocating frame buffer: " << ret << std::endl;
 throw std::runtime_error("Could not allocate audio data buffers.");
 }

 // Copy the audio data into the frame's buffer (interleaving if necessary)
 /*if (codec_ctx->ch_layout.nb_channels == 2) {
 // If stereo, interleave planar data into packed format
 for (int i = 0; i < num_samples; ++i) {
 ((int16_t*)frame->data[0])[2 * i] = ((int16_t*)data_.data())[i]; // Left channel
 ((int16_t*)frame->data[0])[2 * i + 1] = ((int16_t*)data_.data())[total_samples + i]; // Right channel
 }
 }
 else {
 // For mono or packed data, directly copy the samples
 std::memcpy(frame->data[0], data_.data() + samples_read * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * codec_ctx->ch_layout.nb_channels,
 num_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * codec_ctx->ch_layout.nb_channels);
 }
 */
 std::memcpy(frame->data[0], data_.data() + samples_read * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * codec_ctx->ch_layout.nb_channels,
 num_samples * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16) * codec_ctx->ch_layout.nb_channels);

 // Send the frame for encoding
 ret = avcodec_send_frame(codec_ctx, frame);
 if (ret < 0) {
 std::cerr << "Error sending frame for encoding: " << ret << std::endl;
 throw std::runtime_error("Error sending frame for encoding.");
 }

 // Receive and write encoded packets
 while (ret >= 0) {
 ret = avcodec_receive_packet(codec_ctx, pkt);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
 break;
 }
 else if (ret < 0) {
 throw std::runtime_error("Error during encoding.");
 }

 out_file.write(reinterpret_cast(pkt->data), pkt->size);
 av_packet_unref(pkt);
 }

 samples_read += num_samples;
 }

 // Flush the encoder
 if (avcodec_send_frame(codec_ctx, nullptr) < 0) {
 throw std::runtime_error("Error flushing the encoder.");
 }

 while (avcodec_receive_packet(codec_ctx, pkt) >= 0) {
 out_file.write(reinterpret_cast(pkt->data), pkt->size);
 av_packet_unref(pkt);
 }

 // Write file trailer
 av_write_trailer(format_ctx);

 // Cleanup
 av_frame_free(&frame);
 av_packet_free(&pkt);
 avcodec_free_context(&codec_ctx);

 if (!(format_ctx->oformat->flags & AVFMT_NOFILE)) {
 avio_closep(&format_ctx->pb);
 }
 avformat_free_context(format_ctx);

 out_file.close();
 return out_file;
}

</const></char>


Run code :


#include "audio_segment.h"
#include "effects.h"
#include "playback.h"
#include "cppaudioop.h"
#include "exceptions.h"
#include "generators.h"
#include "silence.h"
#include "utils.h"

#include <iostream>
#include <filesystem>

using namespace cppdub;

int main() {
 try {
 // Load the source audio file
 AudioSegment seg_1 = AudioSegment::from_file("../data/test10.mp3");
 std::string out_file_name = "ah-ah-ah.wav";

 // Export the audio segment to a new file with specified settings
 //seg_1.export_segment(out_file_name, "mp3");
 seg_1.export_segment_to_wav_file(out_file_name);


 // Optionally play the audio segment to verify
 // play(seg_1);

 // Load the exported audio file
 AudioSegment seg_2 = AudioSegment::from_file(out_file_name);

 // Play segments
 //play(seg_1);
 play(seg_2);
 }
 catch (const std::exception& e) {
 std::cerr << "An error occurred: " << e.what() << std::endl;
 }

 return 0;
}
</filesystem></iostream>


Error in second call of from_file function :


[pcm_s16le @ 000002d82ca5bfc0] Invalid PCM packet, data has size 2 but at least a size of 4 was expected


The process continue, i call hear the seg_2 with play(seg_2) call, but i can't directly play seg_2 export wav file (from windows explorer).


I had a guess that error may be because packed vs plannar formats missmatch but i am not quit sure. Maybe a swr_convert is necessary.