write AVI file from raw image - c++

I am reading a raw file which is having only 1's and 0's which i have saved from SurfaceFlinger into a character buffer and write to IplImage. Then I am trying to write it to a video file but cvWriteFrame() is returning 0.Can any one help where I am going wrong.
Below is my code.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
FILE * pFile;
long lSize;
char * buffer;
size_t result;
pFile = fopen(argv[1], "rb");
if (pFile == NULL) {
fputs("File error", stderr);
exit(1);
}
// obtain file size:
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile)
rewind(pFile);
// allocate memory to contain the whole file:
buffer = (char*) malloc(sizeof(char) * lSize);
if (buffer == NULL) {
fputs("Memory error", stderr);
exit(2);
}
// copy the file into the buffer:
result = fread(buffer, 1, lSize, pFile);
if (result != lSize) {
fputs("Reading error", stderr);
exit(3);
}
// clean up
fclose(pFile);
IplImage *img;
img = cvCreateImage(cvSize(768, 1280), IPL_DEPTH_8U, 4);
memcpy(img->imageData, buffer, lSize);
cvSaveImage("Displaywindow.png", img);
int width = img->width;
int height = img->height;
CvVideoWriter *writer = cvCreateVideoWriter("out.avi",
CV_FOURCC_DEFAULT,
30,
cvSize(height, width), 1);
if(writer == NULL)
{
printf("error\n");
exit(0);
}
for(int counter=0;counter < 3000;counter++)
{
if(cvWriteFrame(writer,img) == 0)
{
printf("con't write\n");
exit(0);
}
}
waitKey(0);
return 0;
}
I am passing my raw file as argument.

Related

How do I use the FFmpeg libraries to extract every nth frame from a video and save it as a small image file in C++?

After experimenting with the examples on the FFmpeg documentation, I was finally able to create a short program that extracts every nth frame from a video. However, the output files that it produces are huge at over 15mb for each image. How can I change this to produce lower quality images?
The result I am trying to get is done easily on the command line with:
ffmpeg -i [input video] -vf "select=not(mod(n\,10))" -fps_mode vfr img_%03d.jpg
For a video with about 500 frames, this creates 50 images that are only about 800kb each; how am would I be able to mimic this in my program?
My code consists of opening the input file, decoding the packets, then saving the frames:
#include <cstdio>
#include <cstdlib>
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
}
static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
static int video_stream_index = -1;
// OPEN THE INPUT FILE
static int open_input_file(const char *filename) {
// INIT VARS AND FFMPEG OBJECTS
int ret;
const AVCodec *dec;
// OPEN INPUT FILE
if((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
printf("ERROR: failed to open input file\n");
return ret;
}
// FIND STREAM INFO BASED ON INPUT FILE
if((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
printf("ERROR: failed to find stream information\n");
return ret;
}
// FIND THE BEST VIDEO STREAM FOR THE INPUT FILE
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if(ret < 0) {
printf("ERROR: failed to find a video stream in the input file\n");
return ret;
}
video_stream_index = ret;
// ALLOCATE THE DECODING CONTEXT FOR THE INPUT FILE
dec_ctx = avcodec_alloc_context3(dec);
if(!dec_ctx) {
printf("ERROR: failed to allocate decoding context\n");
// CAN NOT ALLOCATE MEMORY ERROR
return AVERROR(ENOMEM);
}
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);
// INIT THE VIDEO DECODER
if((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
printf("ERROR: failed to open video decoder\n");
return ret;
}
return 0;
}
// SAVE THE FILE
static void save(unsigned char *buf, int wrap, int x_size, int y_size, char *file_name) {
// INIT THE EMPTY FILE
FILE *file;
// OPEN AND WRITE THE IMAGE FILE
file = fopen(file_name, "wb");
fprintf(file, "P6\n%d %d\n%d\n", x_size, y_size, 255);
for(int i = 0; i < y_size; i++) {
fwrite(buf + i * wrap, 1, x_size * 3, file);
}
fclose(file);
}
// DECODE FRAME AND CONVERT IT TO AN RGB IMAGE
static void decode(AVCodecContext *cxt, AVFrame *frame, AVPacket *pkt,
const char *out_file_name, const char *file_ext, int mod=1) {
// INIT A BLANK CHAR TO HOLD THE FILE NAME AND AN EMPTY INT TO HOLD FUNCTION RETURN VALUES
char buf[1024];
int ret;
// SEND PACKET TO DECODER
ret = avcodec_send_packet(cxt, pkt);
if(ret < 0) {
printf("ERROR: error sending packet for decoding\n");
exit(1);
}
// CREATE A SCALAR CONTEXT FOR CONVERSION
SwsContext *sws_ctx = sws_getContext(dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, dec_ctx->width,
dec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
// CREATE A NEW RGB FRAME FOR CONVERSION
AVFrame* rgb_frame = av_frame_alloc();
rgb_frame->format = AV_PIX_FMT_RGB24;
rgb_frame->width = dec_ctx->width;
rgb_frame->height = dec_ctx->height;
// ALLOCATE A NEW BUFFER FOR THE RGB CONVERSION FRAME
av_frame_get_buffer(rgb_frame, 0);
// WHILE RETURN COMES BACK OKAY (FUNCTION RETURNS >= 0)...
while(ret >= 0) {
// GET FRAME BACK FROM DECODER
ret = avcodec_receive_frame(cxt, frame);
// IF "RESOURCE TEMP NOT AVAILABLE" OR "END OF FILE" ERROR...
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if(ret < 0) {
printf("ERROR: error during decoding\n");
exit(1);
}
// IF FRAME NUMBER IF THE (MOD)TH FRAME...
if(cxt->frame_number % mod == 0){
// OUTPUT WHICH FRAME IS BEING SAVED
printf("saving frame %03d\n", cxt->frame_number);
// REMOVES TEMPORARY BUFFERED DATA
fflush(stdout);
// SCALE (CONVERT) THE OLD FRAME TO THE NEW RGB FRAME
sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height,
rgb_frame->data, rgb_frame->linesize);
// SET "BUF" TO THE OUTPUT FILE PATH (SAVES TO "out_file_name_###.file_ext")
snprintf(buf, sizeof(buf), "%s_%03d.%s", out_file_name, cxt->frame_number, file_ext);
// SAVE THE FRAME
save(rgb_frame->data[0], rgb_frame->linesize[0], rgb_frame->width, rgb_frame->height, buf);
}
}
}
int main() {
// SIMULATE COMMAND LINE ARGUMENTS
char argv0[] = "test";
char argv1[] = "/User/Desktop/frames/test_video.mov";
char *argv[] = {argv0, argv1, nullptr};
// INIT VARS AND FFMPEG OBJECTS
int ret;
AVPacket *packet;
AVFrame *frame;
// ALLOCATE FRAME AND PACKET
frame = av_frame_alloc();
packet = av_packet_alloc();
if (!frame || !packet) {
fprintf(stderr, "Could not allocate frame or packet\n");
exit(1);
}
// IF FILE DOESN'T OPEN, GO TO THE END
if((ret = open_input_file(argv[1])) < 0) {
goto end;
}
// READ ALL THE PACKETS - simple
while(av_read_frame(fmt_ctx, packet) >= 0) {
// IF PACKET INDEX MATCHES VIDEO INDEX...
if (packet->stream_index == video_stream_index) {
// SEND PACKET TO THE DECODER and SAVE
std::string name = "/User/Desktop/frames/img";
std::string ext = "bmp";
decode(dec_ctx, frame, packet, name.c_str(), ext.c_str(), 5);
}
// UNREFERENCE THE PACKET
av_packet_unref(packet);
}
// END MARKER
end:
avcodec_free_context(&dec_ctx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
av_packet_free(&packet);
// FINAL ERROR CATCH
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
exit(1);
}
exit(0);
}
I am not sure how to go about producing images that are much smaller in size like the ones produced on the command line. I have a feeling that this is possible somehow during the conversion to RGB or the saving of the file but I can't seem to figure out how.
Also, is there any way that I could go about this much more efficiently? On the command line, this finishes very quickly (no more than a second or two for a 9 sec. movie at ~60 fps).
The command line version compresses the frame into jpeg file hence the size is very small. On the other hand, your code writes the rgb values directly into a file (regardless of the file extension). The size of the image is then Height x Width x 3 bytes, which is very big.
Solution: Adjust your save function to also compress the image.
Code example from Github - save_frame_as_jpeg.c:
int save_frame_as_jpeg(AVCodecContext *pCodecCtx, AVFrame *pFrame, int FrameNo)
{
AVCodec *jpegCodec = avcodec_find_encoder(AV_CODEC_ID_JPEG2000);
if (!jpegCodec) { return -1; }
AVCodecContext *jpegContext = avcodec_alloc_context3(jpegCodec);
if (!jpegContext) { return -1; }
jpegContext->pix_fmt = pCodecCtx->pix_fmt;
jpegContext->height = pFrame->height;
jpegContext->width = pFrame->width;
if (avcodec_open2(jpegContext, jpegCodec, NULL) < 0)
{ return -1; }
FILE *JPEGFile;
char JPEGFName[256];
AVPacket packet = {.data = NULL, .size = 0};
av_init_packet(&packet);
int gotFrame;
if (avcodec_encode_video2(jpegContext, &packet, pFrame, &gotFrame) < 0)
{ return -1; }
sprintf(JPEGFName, "dvr-%06d.jpg", FrameNo);
JPEGFile = fopen(JPEGFName, "wb");
fwrite(packet.data, 1, packet.size, JPEGFile);
fclose(JPEGFile);
av_free_packet(&packet);
avcodec_close(jpegContext);
return 0;
}

How to save AVFrame as image in C++ using FFmpeg

In my project, i'd like to save one of the frames from Hevc file. I'm using FFmpeg in source code to decode the Hevc file and get AVFrame and AVCodecContext.
What i need is to save the frame as picture(with full colors).
I have tried to save it as *.pgm file, so the picture is just grey, which not really i need.
Any suggesstion? Thanks!
void HevcDecoder::Images_Save(char* filename, AVFrame *frame)
{
FILE* file;
int i;
fopen_s(&file, filename, "wb");
fprintf(file, "P5\n%d %d\n%d\n", frame->width, frame->height, 255);
for (i = 0; i < frame->height; i++)
fwrite(frame->data[0] + i * frame->linesize[0], 1, frame->width, file);
fclose(file);
}
void HevcDecoder::Decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt, const char* filename)
{
char buf[1024];
int ret;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", dec_ctx->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
snprintf(buf, sizeof(buf), "%s-%d.pgm", filename, dec_ctx->frame_number);
Images_Save(buf, frame/*, dec_ctx*/);
}
}
Converting raw HEVC file to sequence of images image using FFmpeg CLI, is simple.
Assume input.265 is the input file (raw HEVC video stream):
Converting to PNG images:
ffmpeg -i input.265 %05d.png
Converting to PPM images:
ffmpeg -i input.265 %05d.ppm
In case the input video uses MP4 container and you want JPEG images:
ffmpeg -i input.265 %05d.jpg
Using FFmpeg C interface (Libav):
For making things reproducible, start by creating an input video file using FFmpeg CLI:
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -vcodec libx265 -pix_fmt yuv420p input.265
The above command creates HEVC (H.265) encoded stream - 10 frames with resolution 192x108 and pixel format YUV420 (synthetic pattern).
The encoded stream is raw video stream (without container).
Note:
RAW HEVC (H.265) video stream is not commonly used file format.
Usually the stream is wrapped by container (like MP4 / MKV / AVI...).
We use the raw video stream for educational purposes - the code used for decoding is simpler.
Saving the images as color images:
The code sample reuses the code from the this post.
PGM is a grayscale format, for equivalent color format we may use PPM format.
We may use SWS Scale to convert the format from YUV420 to RGB.
We can use the code sample from this post
Here is the code sample:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
#define INBUF_SIZE 1024
//static void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize, char* filename)
//{
// FILE* f;
// int i;
//
// f = fopen(filename, "wb");
// fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
// for (i = 0; i < ysize; i++)
// fwrite(buf + i * wrap, 1, xsize, f);
// fclose(f);
//}
//Save RGB image as PPM file format
static void ppm_save(unsigned char* buf, int wrap, int xsize, int ysize, char* filename)
{
FILE* f;
int i;
f = fopen(filename, "wb");
fprintf(f, "P6\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
{
fwrite(buf + i * wrap, 1, xsize*3, f);
}
fclose(f);
}
static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt, const char* filename)
{
struct SwsContext* sws_ctx = NULL;
char buf[1024];
int ret;
int sts;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
//Create SWS Context for converting from decode pixel format (like YUV420) to RGB
////////////////////////////////////////////////////////////////////////////
sws_ctx = sws_getContext(dec_ctx->width,
dec_ctx->height,
dec_ctx->pix_fmt,
dec_ctx->width,
dec_ctx->height,
AV_PIX_FMT_RGB24,
SWS_BICUBIC,
NULL,
NULL,
NULL);
if (sws_ctx == nullptr)
{
return; //Error!
}
////////////////////////////////////////////////////////////////////////////
//Allocate frame for storing image converted to RGB.
////////////////////////////////////////////////////////////////////////////
AVFrame* pRGBFrame = av_frame_alloc();
pRGBFrame->format = AV_PIX_FMT_RGB24;
pRGBFrame->width = dec_ctx->width;
pRGBFrame->height = dec_ctx->height;
sts = av_frame_get_buffer(pRGBFrame, 0);
if (sts < 0)
{
return; //Error!
}
////////////////////////////////////////////////////////////////////////////
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
return;
}
else if (ret < 0)
{
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", dec_ctx->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
//snprintf(buf, sizeof(buf), "%s_%03d.pgm", filename, dec_ctx->frame_number);
//pgm_save(frame->data[0], frame->linesize[0],
// frame->width, frame->height, buf);
//Convert from input format (e.g YUV420) to RGB and save to PPM:
////////////////////////////////////////////////////////////////////////////
sts = sws_scale(sws_ctx, //struct SwsContext* c,
frame->data, //const uint8_t* const srcSlice[],
frame->linesize, //const int srcStride[],
0, //int srcSliceY,
frame->height, //int srcSliceH,
pRGBFrame->data, //uint8_t* const dst[],
pRGBFrame->linesize); //const int dstStride[]);
if (sts != frame->height)
{
return; //Error!
}
snprintf(buf, sizeof(buf), "%s_%03d.ppm", filename, dec_ctx->frame_number);
ppm_save(pRGBFrame->data[0], pRGBFrame->linesize[0], pRGBFrame->width, pRGBFrame->height, buf);
////////////////////////////////////////////////////////////////////////////
}
//Free
sws_freeContext(sws_ctx);
av_frame_free(&pRGBFrame);
}
int main(int argc, char** argv)
{
const char* filename, * outfilename;
const AVCodec* codec;
AVCodecParserContext* parser;
AVCodecContext* c = NULL;
FILE* f;
AVFrame* frame;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t* data;
size_t data_size;
int ret;
AVPacket* pkt;
filename = argv[1];
outfilename = argv[2];
pkt = av_packet_alloc();
if (!pkt)
{
exit(1);
}
//memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
memset(inbuf, 0, sizeof(inbuf));
codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser)
{
fprintf(stderr, "parser not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c)
{
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
if (avcodec_open2(c, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f)
{
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
while (!feof(f))
{
/* read raw data from the input file */
data_size = fread(inbuf, 1, INBUF_SIZE, f);
if (!data_size)
{
break;
}
/* use the parser to split the data into frames */
data = inbuf;
while (data_size > 0)
{
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, data, (int)data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0)
{
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->data)
{
printf("NICE\n");
decode(c, frame, pkt, outfilename);
}
}
}
/* flush the decoder */
decode(c, frame, NULL, outfilename);
fclose(f);
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
Showing images using OpenCV:
One of the simplest ways to show an image is using OpenCV library.
Setting up a project that uses both FFmpeg and OpenCV for the first time may be challenging.
We need the image to be in BGR format.
For showing the image, use: cv::imshow followed by cv::waitKey.
Code sample:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Use OpenCV for showing the inage
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
#define INBUF_SIZE 1024
//static void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize, char* filename)
//{
// FILE* f;
// int i;
//
// f = fopen(filename, "wb");
// fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
// for (i = 0; i < ysize; i++)
// fwrite(buf + i * wrap, 1, xsize, f);
// fclose(f);
//}
//Save RGB image as PPM file format
//static void ppm_save(unsigned char* buf, int wrap, int xsize, int ysize, char* filename)
//{
// FILE* f;
// int i;
//
// f = fopen(filename, "wb");
// fprintf(f, "P6\n%d %d\n%d\n", xsize, ysize, 255);
//
// for (i = 0; i < ysize; i++)
// {
// fwrite(buf + i * wrap, 1, xsize*3, f);
// }
//
// fclose(f);
//}
static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt, const char* filename)
{
struct SwsContext* sws_ctx = NULL;
char filename_buf[1024];
int ret;
int sts;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
//Create SWS Context for converting from decode pixel format (like YUV420) to BGR
////////////////////////////////////////////////////////////////////////////
sws_ctx = sws_getContext(dec_ctx->width,
dec_ctx->height,
dec_ctx->pix_fmt,
dec_ctx->width,
dec_ctx->height,
AV_PIX_FMT_BGR24, //For OpenCV, we want BGR pixel format.
SWS_BICUBIC,
NULL,
NULL,
NULL);
if (sws_ctx == nullptr)
{
return; //Error!
}
////////////////////////////////////////////////////////////////////////////
//Allocate frame for storing image converted to RGB.
////////////////////////////////////////////////////////////////////////////
AVFrame* pBGRFrame = av_frame_alloc();
pBGRFrame->format = AV_PIX_FMT_BGR24;
pBGRFrame->width = dec_ctx->width;
pBGRFrame->height = dec_ctx->height;
sts = av_frame_get_buffer(pBGRFrame, 0);
if (sts < 0)
{
return; //Error!
}
////////////////////////////////////////////////////////////////////////////
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
return;
}
else if (ret < 0)
{
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", dec_ctx->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
//snprintf(buf, sizeof(buf), "%s_%03d.pgm", filename, dec_ctx->frame_number);
//pgm_save(frame->data[0], frame->linesize[0],
// frame->width, frame->height, buf);
//Convert from input format (e.g YUV420) to BGR:
////////////////////////////////////////////////////////////////////////////
sts = sws_scale(sws_ctx, //struct SwsContext* c,
frame->data, //const uint8_t* const srcSlice[],
frame->linesize, //const int srcStride[],
0, //int srcSliceY,
frame->height, //int srcSliceH,
pBGRFrame->data, //uint8_t* const dst[],
pBGRFrame->linesize); //const int dstStride[]);
if (sts != frame->height)
{
return; //Error!
}
snprintf(filename_buf, sizeof(filename_buf), "%s_%03d.jpg", filename, dec_ctx->frame_number);
//ppm_save(pBGRFrame->data[0], pBGRFrame->linesize[0], pBGRFrame->width, pBGRFrame->height, buf);
////////////////////////////////////////////////////////////////////////////
//Use OpenCV for showing the image (and save the image in JPEG format):
////////////////////////////////////////////////////////////////////////////
cv::Mat img = cv::Mat(pBGRFrame->height, pBGRFrame->width, CV_8UC3, pBGRFrame->data[0], pBGRFrame->linesize[0]); //cv::Mat is OpenCV "thin image wrapper".
cv::imshow("img", img);
cv::waitKey(100); //Wait 100msec (relativly long time - for testing).
//Save the inage in JPEG format using OpenCV
cv::imwrite(filename_buf, img);
////////////////////////////////////////////////////////////////////////////
}
//Free
sws_freeContext(sws_ctx);
av_frame_free(&pBGRFrame);
}
int main(int argc, char** argv)
{
const char* filename, * outfilename;
const AVCodec* codec;
AVCodecParserContext* parser;
AVCodecContext* c = NULL;
FILE* f;
AVFrame* frame;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
uint8_t* data;
size_t data_size;
int ret;
AVPacket* pkt;
filename = argv[1];
outfilename = argv[2];
pkt = av_packet_alloc();
if (!pkt)
{
exit(1);
}
//memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
memset(inbuf, 0, sizeof(inbuf));
codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser)
{
fprintf(stderr, "parser not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c)
{
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
if (avcodec_open2(c, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "rb");
if (!f)
{
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
while (!feof(f))
{
/* read raw data from the input file */
data_size = fread(inbuf, 1, INBUF_SIZE, f);
if (!data_size)
{
break;
}
/* use the parser to split the data into frames */
data = inbuf;
while (data_size > 0)
{
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, data, (int)data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0)
{
fprintf(stderr, "Error while parsing\n");
exit(1);
}
data += ret;
data_size -= ret;
if (pkt->data)
{
printf("NICE\n");
decode(c, frame, pkt, outfilename);
}
}
}
/* flush the decoder */
decode(c, frame, NULL, outfilename);
fclose(f);
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
Sample output:
output_001.jpg:
output_002.jpg:
output_003.jpg:

zlib decompression return -3 (z_data_error)

The zlib uncompress() return -3 (z_data_error) when I decompress data.
From doc: returns Z_DATA_ERROR if the input data was corrupted or incomplete,
uncompress((Bytef*)uncompressbuffer, &uncompressbuffersize, (const Bytef*)compressbuffer, &compressbuffersize)
In another application, where I use deflate/inflate I get the same error.
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = inputLength;
strm.next_in = (unsigned char*) inputBuffer;
ret = inflateInit(&strm);
if (ret != Z_OK)
{
delete[] uncompressedData;
return ERROR;
}
/******************************************************/
strm.avail_out = unusedData;
strm.next_out = (uncompressedData + MIN_CHUNK) - unusedData;
/* run inflate() on input until output buffer not full */
do {
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
} while (strm.avail_out != 0 && ret == Z_OK);
but
this error happens only with x64 version of my software. A x86 working properly. The unzipped data is intact. The buffer size of compressed and uncompressed data are correct.
Zlib is correctly compiled to x64.
What else could be causing this problem? Any hint?
Sample code with "uncompress":
#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>
#define CHUNK 16384
const int BUFFERSIZE = 4096;
using namespace std;
void compress(FILE* fin, FILE* fout) {
char buffer[BUFFERSIZE];
int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);
z_stream strm;
int ret;
unsigned have;
unsigned char* tmp = new unsigned char[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = (unsigned char*)buffer;
strm.avail_in = byte_read;
strm.next_out = tmp;
strm.avail_out = CHUNK;
ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
//first loop: compress input data stream and write on RTDB file
do
{
ret = deflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR);
have = BUFFERSIZE - strm.avail_out;
fwrite(tmp, sizeof(char), BUFFERSIZE, fout);
} while (strm.avail_out == 0);
//assert(strm.avail_in == 0);
//second loop: all input data consumed. Flush everything...
do
{
strm.next_out = tmp;
strm.avail_out = BUFFERSIZE;
ret = deflate(&strm, Z_FINISH);
assert(ret != Z_STREAM_ERROR);
have = BUFFERSIZE - strm.avail_out;
fwrite(tmp, sizeof(char), BUFFERSIZE, fout);
} while (ret != Z_STREAM_END);
(void)deflateEnd(&strm);
delete tmp;
}
void decompress(FILE* fin, FILE* fout) {
int status;
char buffer[BUFFERSIZE];
int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);
void* compressedBuffer;
void* uncompressedBuffer;
uLongf compressedBufferSize = BUFFERSIZE;
uLongf uncompressedBufferSize = BUFFERSIZE;
compressedBuffer = malloc(compressedBufferSize);
uncompressedBuffer = malloc(uncompressedBufferSize);
status = uncompress((Bytef*)uncompressedBuffer, &uncompressedBufferSize, (const Bytef*)buffer, compressedBufferSize);
fwrite(uncompressedBuffer, sizeof(char), BUFFERSIZE, fout);
cout << "Status " << status << endl;
}
int main(int argc, char *argv[]) {
//if (argc == 2)
//{
// if (strcmp(argv[1], "/?") == 0 || strcmp(argv[1], "--help") == 0)
// {
// cout << "Please give me 1 argument" << endl;
// //getchar();
// return -1;
// }
//}
//else
//{
// cout << "Please give me 1 argument" << endl;
// //getchar();
// return -1;
//}
//char *inputdata = argv[1];
//const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\P0000P0000_no_com-alt.rtdb";
const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\AAA.txt";
//const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\P0000P0000_no_com-alt.rtdb";
cout << inputdata << endl;
FILE *fin, *fout, *fdec;
fopen_s(&fin, inputdata, "r+");
fopen_s(&fout, "output.txt", "w+");
compress(fin, fout);
fclose(fin);
fclose(fout);
fopen_s(&fout, "output.txt", "r");
fopen_s(&fdec, "dec.txt", "w");
decompress(fout, fdec);
fclose(fout);
fclose(fdec);
}
Your first problem is that as you are using windows you must open the compressed file in binary mode otherwise it will be corrupted:
fopen_s(&fout, "output.txt", "w+b");
fopen_s(&fout, "output.txt", "rb");
if the file you are compressing isn't text or if it is text and you want to perfectly preserve it you should also open the input and dec files in binary mode.
Next in compress you confuse BUFFERSIZE and CHUNK, have = BUFFERSIZE - strm.avail_out; should be have = CHUNK - strm.avail_out;, you then need to pass have to fwrite: fwrite(tmp, sizeof(char), have, fout);.
In decompress you need to pass uncompressedBufferSize to fwrite instead of BUFFERSIZE.
Fully working code (with some additional changes to fix memory leaks):
#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>
#include <array>
const size_t CHUNK_SIZE = 16384;
const size_t BUFFER_SIZE = 4096;
void compress(FILE* fin, FILE* fout) {
std::array<Bytef, BUFFER_SIZE> buffer;
int byte_read = fread(buffer.data(), sizeof(char), buffer.size(), fin);
z_stream strm;
int ret;
unsigned have;
std::vector<Bytef> tmp(CHUNK_SIZE);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.next_in = buffer.data();
strm.avail_in = byte_read;
strm.next_out = tmp.data();
strm.avail_out = tmp.size();
ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
//first loop: compress input data stream and write on RTDB file
do
{
ret = deflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR);
have = tmp.size() - strm.avail_out;
fwrite(tmp.data(), sizeof(char), have, fout);
} while (strm.avail_out == 0);
//assert(strm.avail_in == 0);
//second loop: all input data consumed. Flush everything...
do
{
strm.next_out = tmp.data();
strm.avail_out = tmp.size();
ret = deflate(&strm, Z_FINISH);
assert(ret != Z_STREAM_ERROR);
have = tmp.size() - strm.avail_out;
fwrite(tmp.data(), sizeof(char), have, fout);
} while (ret != Z_STREAM_END);
(void)deflateEnd(&strm);
}
void decompress(FILE* fin, FILE* fout) {
int status;
std::array<Bytef, BUFFER_SIZE> compressedBuffer;
std::array<Bytef, BUFFER_SIZE> uncompressedBuffer;
int byte_read = fread(compressedBuffer.data(), sizeof(char), compressedBuffer.size(), fin);
uLongf compressedBufferSize = compressedBuffer.size();
uLongf uncompressedBufferSize = uncompressedBuffer.size();
status = uncompress(uncompressedBuffer.data(), &uncompressedBufferSize, compressedBuffer.data(), compressedBufferSize);
fwrite(uncompressedBuffer.data(), sizeof(char), uncompressedBufferSize, fout);
std::cout << "Status " << status << "\n";
}
int main(int argc, char* argv[]) {
const char* inputdata = "C:\\Users\\alan\\source\\repos\\ConanScratch\\main.cpp";
std::cout << inputdata << "\n";
FILE* fin, * fout, * fdec;
fopen_s(&fin, inputdata, "r+b");
if (!fin)
{
std::cout << "unable to open input\n";
return -1;
}
fopen_s(&fout, "output.txt", "w+b");
if (!fout)
{
std::cout << "unable to open output\n";
return -1;
}
compress(fin, fout);
fclose(fin);
fclose(fout);
fopen_s(&fout, "output.txt", "r+b");
if (!fout)
{
std::cout << "unable to open output\n";
return -1;
}
fopen_s(&fdec, "dec.txt", "wb");
if (!fdec)
{
std::cout << "unable to open dec\n";
return -1;
}
decompress(fout, fdec);
fclose(fout);
fclose(fdec);
}
Your code can be greatly simplified with boost::iostreams:
#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/zlib.hpp>
int main(int argc, char* argv[])
{
{
std::ifstream input("C:\\Users\\alan\\source\\repos\\ConanScratch\\main.cpp", std::ios_base::binary);
boost::iostreams::filtering_ostream output;
output.push(boost::iostreams::zlib_compressor{});
output.push(boost::iostreams::file_sink("output.txt", std::ios_base::out | std::ios_base::binary));
output << input.rdbuf();
}
{
boost::iostreams::filtering_istream input;
input.push(boost::iostreams::zlib_decompressor{});
input.push(boost::iostreams::file_source("output.txt", std::ios_base::in | std::ios_base::binary));
std::ofstream output("dec.txt", std::ios_base::binary);
output << input.rdbuf();
}
}

Reading mp3 file using ffmpeg caues memory leaks, even after freeing it in main

i am continuously reading mp3 files and processing them, but the memory keeps getting build up even though i freed it.
At the bottom read_audio_mp3(), they are already freeing some variable.
why do i still face a memory build up and how do i deal with it ?
following this code : https://rodic.fr/blog/libavcodec-tutorial-decode-audio-file/, i read mp3 using this function
int read_audio_mp3(string filePath_str, const int sample_rate,
double** output_buffer, int &AUDIO_DURATION){
const char* path = filePath_str.c_str();
/* Reads the file header and stores information about the file format. */
AVFormatContext* format = avformat_alloc_context();
if (avformat_open_input(&format, path, NULL, NULL) != 0) {
fprintf(stderr, "Could not open file '%s'\n", path);
return -1;
}
/* Check out the stream information in the file. */
if (avformat_find_stream_info(format, NULL) < 0) {
fprintf(stderr, "Could not retrieve stream info from file '%s'\n", path);
return -1;
}
/* find an audio stream. */
int stream_index =- 1;
for (unsigned i=0; i<format->nb_streams; i++) {
if (format->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index == -1) {
fprintf(stderr, "Could not retrieve audio stream from file '%s'\n", path);
return -1;
}
AVStream* stream = format->streams[stream_index];
// find & open codec
AVCodecContext* codec = stream->codec;
if (avcodec_open2(codec, avcodec_find_decoder(codec->codec_id), NULL) < 0) {
fprintf(stderr, "Failed to open decoder for stream #%u in file '%s'\n", stream_index, path);
return -1;
}
// prepare resampler
struct SwrContext* swr = swr_alloc();
av_opt_set_int(swr, "in_channel_count", codec->channels, 0);
av_opt_set_int(swr, "out_channel_count", 1, 0);
av_opt_set_int(swr, "in_channel_layout", codec->channel_layout, 0);
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr, "in_sample_rate", codec->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", codec->sample_fmt, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
swr_init(swr);
if (!swr_is_initialized(swr)) {
fprintf(stderr, "Resampler has not been properly initialized\n");
return -1;
}
/* Allocate an audio frame. */
AVPacket packet;
av_init_packet(&packet);
AVFrame* frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Error allocating the frame\n");
return -1;
}
// iterate through frames
*output_buffer = NULL;
AUDIO_DURATION = 0;
while (av_read_frame(format, &packet) >= 0) {
// decode one frame
int gotFrame;
if (avcodec_decode_audio4(codec, frame, &gotFrame, &packet) < 0) {
// free packet
av_free_packet(&packet);
break;
}
if (!gotFrame) {
// free packet
av_free_packet(&packet);
continue;
}
// resample frames
double* buffer;
av_samples_alloc((uint8_t**) &buffer, NULL, 1, frame->nb_samples, AV_SAMPLE_FMT_DBL, 0);
int frame_count = swr_convert(swr, (uint8_t**) &buffer, frame->nb_samples, (const uint8_t**) frame->data, frame->nb_samples);
// append resampled frames to output_buffer
*output_buffer = (double*) realloc(*output_buffer,
(AUDIO_DURATION + frame->nb_samples) * sizeof(double));
memcpy(*output_buffer + AUDIO_DURATION, buffer, frame_count * sizeof(double));
AUDIO_DURATION += frame_count;
// free buffer & packet
av_free_packet(&packet);
av_free( buffer );
}
// clean up
av_frame_free(&frame);
swr_free(&swr);
avcodec_close(codec);
avformat_free_context(format);
return 0;
}
Main Script : MemoryLeak.cpp
// imports
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <sys/time.h>
extern "C"
{
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
}
using namespace std;
int main (int argc, char ** argv) {
string wavpath = argv[1];
printf("wavpath=%s\n", wavpath.c_str());
printf("\n==== Params =====\n");
// Init
int AUDIO_DURATION;
int sample_rate = 8000;
av_register_all();
printf("\n==== Reading MP3 =====\n");
while (true) {
// Read mp3
double* buffer;
if (read_audio_mp3(wavpath, sample_rate, &buffer, AUDIO_DURATION) != 0) {
printf("Cannot read %s\n", wavpath.c_str());
continue;
}
/*
Process the buffer for down stream tasks.
*/
// Freeing the buffer
free(buffer);
}
return 0 ;
}
Compiling
g++ -o ./MemoryLeak.out -Ofast -Wall -Wextra \
-std=c++11 "./MemoryLeak.cpp" \
-lavformat -lavcodec -lavutil -lswresample
Running, by right my input an argument wav.scp that reads text file of all the mp3s.
But for easy to replicate purpose, i only read 1 file song.mp3 in and i keep re-reading it
./MemoryLeak.out song.mp3
Why do i know i have memory leaks?
I was running up 32 jobs in parallel for 14 million files, and when i wake up in the morning, they were abruptly killed.
I run htop and i monitor the progress when i re-run it, and i saw that the VIRT & RES & Mem are continuously increasing.
Edit 1:
My setup :
ffmpeg version 2.8.15-0ubuntu0.16.04.1
built with gcc 5.4.0

Wma decoding with ffmpeg

I am new to ffmpeg and I tried using api-example.c to decode wma files. However when I run the program, it gave me an error saying
"frame_len overflow". Does anyone know how to fix this error?
Here is my code:
extern "C" {
#include <avcodec.h>
#include "../libavcodec/avcodec.h"
#include <avformat.h>
}
#include <iostream>
#include <assert.h>
#include <windows.h>
#include <mmsystem.h>
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
int main(int argc, char *argv[]) {
avcodec_init();
avcodec_register_all();
//avdevice_register_all();
av_register_all();
AVCodec *codec;
AVCodecContext *c= NULL;
AVCodec *ocodec;
AVCodecContext *oc= NULL;
int out_size, len,out_size2;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
char* outfilename="test.wma";
char* filename="Beethoven's.wma";
AVFormatContext *pFormatCtx;
WAVEFORMATEX* wfx=new WAVEFORMATEX;
int ret;
ret=av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL);
if(ret!=0)
{
std::cout<<"cannot open file!"<<std::endl;
exit(1);
}
if(av_find_stream_info(pFormatCtx)<0)
{
std::cout<<"cannot find stream!"<<std::endl;
exit(1);
}
int audioStream;
AVCodecContext *pCodecCtx;
// Find the first video stream
audioStream=-1;
for(int i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO)
{
audioStream=i;
break;
}
if(audioStream==-1)
{
std::cout<<"cannot find audio!"<<std::endl;
}
// Get a pointer to the codec context for the audio stream
pCodecCtx=pFormatCtx->streams[audioStream]->codec;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the suitable audio decoder */
codec = avcodec_find_decoder(pCodecCtx->codec_id);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
if(codec->capabilities & CODEC_CAP_TRUNCATED)
pCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
//open the codec (for decoding)
int test = avcodec_open(pCodecCtx, codec);
if (test < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
//find mp3 encoder
ocodec = avcodec_find_encoder(CODEC_ID_MP3);
if (!ocodec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
//allocate context
oc= avcodec_alloc_context();
/* put sample parameters */
oc->bit_rate = 64000;
oc->sample_rate = 44100;
oc->channels = 1;
/* open it */
if (avcodec_open(oc, ocodec) < 0) {
fprintf(stderr, "could not open encoding codec\n");
exit(1);
}
//buffer
outbuf = (uint8_t*)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
//open inputfile
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
//open outputfile
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
exit(1);
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
//while there is still data
while (avpkt.size > 0) {
std::cout<<"decoding..."<<std::endl;
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
//decode
len = avcodec_decode_audio3(pCodecCtx, (short *)outbuf, &out_size, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
std::cout<<"1 frame decoded!"<<std::endl;
out_size2 = avcodec_encode_audio(oc, outbuf, out_size, (short*)outbuf);
fwrite(outbuf, 1, out_size2, outfile);
}
//subtract data from whatever decode function returns
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
I have been stuck on this for quite a long time. Please help me.
anyone know whats wrong with my code?
Thanks,
Izak
Use debug messages to determine the point of failure.
Though I am of the strong opinion that this error occurs while encoding, because you are using the same buffer and respective buffer size.