I am attempting to write a progressive reader using libpng. I have tried to follow the code in example.c provided with libpng source but it does not work. I have also looked at libpng doc. Which instructs you to use png_set_progressive_read_fn() in connection with png_process_data(). After setting up things as specified in the documentation. When I go to start the process of having the png file read I get the following error from libpng.
Not a PNG file
Stepping through the code reveals that when png_process_data() goes to check the signature of the PNG file, it identifies that it is not a png file. This is very peculiar behavior since before I call my read function I verify the file is a PNG file with the following bit of code.
int check_png_sig(const char * file_name)
{
FILE *fp = fopen(file_name, "rb");
if(!fp) {
return (0);
}
enum HeaderSize {Size = 8};
png_byte header[Size];
fread(header, 1, Size, fp);
int is_png = !png_sig_cmp(header, 0, Size);
if (!is_png) {
fclose(fp);
return (0);
}
fclose(fp);
return (1);
}
I close the FILE* and then reopen a new one in my read function so I don't have to tell libpng that I have already read 8 bytes with png_set_sig_bytes(png_ptr, 8);. My read function is as follows.
int read_png_file(const char * file_name)
{
fprintf(stdout, "Reading PNG File %s\n", file_name);
fflush(stdout);
if (!png_ptr || !info_ptr) {
return (0);
}
FILE *fp = fopen(file_name, "rb");
if(!fp) {
return (0);
}
png_init_io(png_ptr, fp);
png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr);
/*
* Tell libpng to call read_chunk_callback if an unknown chunk is
* encountered
*/
png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback);
/*
* Tell libpng to call read_row_callback if an known chunk is
* encountered.
*/
png_set_read_status_fn(png_ptr, read_row_callback);
/*
* Tell libpng to call the specified functions on info, rows, or
* end.
*/
png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback,
row_callback, end_callback);
enum Size {DataSize = 8};
unsigned char rawbuf[DataSize];
int process = 1;
if (setjmp(png_jmpbuf(png_ptr))) {
free_png_resources();
process = 0;
return process;
}
/*
* Check to see if libpng is confused
*/
//png_set_sig_bytes(png_ptr, 8);
while (process) {
memset(rawbuf, 0, DataSize);
png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
}
fclose(fp);
return (process);
}
I also have a working version of a non-porgressive reader at (non-progressive reader). It works just fine on my file. So it is not an issue with my file.
COMPLETE CODE
#include <png.h>
#include <stdlib.h>
static png_structp png_ptr;
static png_infop info_ptr;
static png_bytep old_row = NULL;
/* Variable that loops untill data is read */
int run = 0;
//-------------------------------------------------------------------
// Callbacks
int read_chunk_callback(png_structp png_ptr, png_unknown_chunkp chunk)
{
struct chunk
{
png_byte name[5];
png_byte *data;
png_size_t size;
};
return (0); /* did not recognize */
}
/*
* This method will be called each time a row is read
* and differs from the row_callback in that ...
*/
void read_row_callback(png_structp ptr, png_uint_32 row, int pass)
{
fprintf(stderr, "read_row_callback\n");
}
int process_data(png_bytep buffer, png_uint_32 length)
{
fprintf(stderr, "process_data\n");
png_process_data(png_ptr, info_ptr, buffer, length);
return 0;
}
void info_callback(png_structp png_ptr, png_infop info)
{
fprintf(stderr, "info_callback\n");
png_uint_32 width;
png_uint_32 height;
int bit_depth;
int color_type;
int interlace_type;
int compression_type;
int filter_type;
png_byte channels;
png_uint_32 rowbytes;
png_bytep signature;
/*
* This will get the information stored in the header
* of the PNG file.
*/
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
/*
* Get the rest of the header information.
*/
channels = png_get_channels(png_ptr, info_ptr);
/* This is subject to change with transformations */
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
signature = png_get_signature(png_ptr, info_ptr);
fprintf(stdout,
"width: %u"
"height: %u"
"bit_depth: %d"
"color_type: %d"
"interlace_type: %d"
"compression_type: %d"
"filter_type: %d"
"channles: %d"
"rowbytes: %u"
"signature: %s", (unsigned int)width, (unsigned int)height, bit_depth, color_type,
interlace_type, compression_type, filter_type, channels,
(unsigned int)rowbytes, signature);
}
void row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num,
int pass)
{
fprintf(stderr, "row_callback\n");
png_progressive_combine_row(png_ptr, old_row, new_row);
}
void end_callback(png_structp png_ptr, png_infop info)
{
fprintf(stderr, "end_callback\n");
run = 1;
}
/*
* Error handler local to his translation unit
* Used by png_create_read_struct function.
*/
void progressive_reader_error_fn(png_structp png_ptr, png_const_charp msg)
{
fprintf(stderr, "error: %s\n", msg);
fflush(stderr);
longjmp(png_jmpbuf(png_ptr), 1);
exit(0);
}
//-------------------------------------------------------------------
/*
* Free PNG resources on close
*/
void free_png_resources()
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
png_ptr = NULL;
info_ptr = NULL;
}
/*
* All strings to this function must
* be null terminated -- return 0 if
* file is not in png format
*/
int check_png_sig(const char * file_name)
{
FILE *fp = fopen(file_name, "rb");
if(!fp) {
return (0);
}
enum HeaderSize {Size = 8};
png_byte header[Size];
fread(header, 1, Size, fp);
int is_png = !png_sig_cmp(header, 0, Size);
if (!is_png) {
fclose(fp);
return (0);
}
fclose(fp);
return (1);
}
/*
* Create the png_structp and png_infop
*/
int create_png_structs()
{
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
progressive_reader_error_fn, NULL);
if (!png_ptr) {
return 0;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return 0;
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return 0;
}
return 1;
}
/*
* This method does all the work
*/
int read_png_file(const char * file_name)
{
fprintf(stdout, "Reading PNG File %s\n", file_name);
fflush(stdout);
if (!png_ptr || !info_ptr) {
return (0);
}
FILE *fp = fopen(file_name, "rb");
if(!fp) {
return (0);
}
png_init_io(png_ptr, fp);
png_voidp user_chunkp = png_get_user_chunk_ptr(png_ptr);
/*
* Tell libpng to call read_chunk_callback if an unknown chunk is
* encountered
*/
png_set_read_user_chunk_fn(png_ptr, user_chunkp, read_chunk_callback);
/*
* Tell libpng to call read_row_callback if an known chunk is
* encountered.
*/
png_set_read_status_fn(png_ptr, read_row_callback);
/*
* Tell libpng to call the specified functions on info, rows, or
* end.
*/
png_set_progressive_read_fn(png_ptr, user_chunkp, info_callback,
row_callback, end_callback);
enum Size {DataSize = 8};
unsigned char rawbuf[DataSize];
int process = 1;
if (setjmp(png_jmpbuf(png_ptr))) {
free_png_resources();
process = 0;
return process;
}
/*
* Check to see if libpng is confused
*/
//png_set_sig_bytes(png_ptr, 8);
while (process) {
memset(rawbuf, 0, DataSize);
png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
}
fclose(fp);
return (process);
}
int main(int argc, char *argv[])
{
if (check_png_sig("/home/matt6809/Downloads/png_image.png")) {
if (create_png_structs()) {
if (read_png_file("/home/matt6809/Downloads/png_image.png")) {
fprintf(stderr, "SUCCESS!!!\n");
}
}
}
return 0;
}
Makefile
CC = /usr/bin/gcc
LD = /usr/bin/gcc
CFLAGS = -c -Wall -g
LDFLAGS = -lpng
SRC = $(wildcard *.c)
OBJ = $(SRC:%.c=%.o)
TARGET = progressive
all : $(TARGET)
$(TARGET) : $(OBJ)
$(LD) $(LDFLAGS) $^ -o $(TARGET)
%.o : %.c
$(CC) $(CFLAGS) -o $# $<
clean :
rm -rf *.o $(TARGET)
You've forgotten to read the content from your file.
Replacing:
while (process) {
memset(rawbuf, 0, DataSize);
png_process_data(png_ptr, info_ptr, rawbuf, DataSize);
}
with
size_t read;
while ((read = fread(rawbuf, 1, DataSize, fp))) {
png_process_data(png_ptr, info_ptr, rawbuf, read);
}
is enough to allow decoding to proceed.
I did notice one other thing: the second parameters passed to png_set_read_user_chunk_fn() and png_set_progressive_read_fn() are supposed to be arbitrary values that the callback functions can get hold of later (via png_get_user_chunk_ptr() and png_get_progressive_ptr(), respectively).
These can be set to whatever values you like (or to NULL if you don't need them), but you shouldn't be calling the png_get_*_ptr() functions yourself to get a value to pass to png_set_*_fn(). (I think it's harmless, since they'll return NULL to start with, but it's confusing at best.)
Related
I'm trying to send .amr files from my desktop to a SIM900 GSM module over UART.
I'm using teuniz's RS232 library.
I do the initialisation using AT commands and then read the file into a buffer and write it to the UART using the RS232_SendByte() library function byte-by-byte, but it doesn't seem to work.
I send the following AT commands:
AT+CFSINIT
AT+CFSWFILE=\"audio.amr\",0,6694,13000 # After which I get the CONNECT message from the SIM900 module
# Here's where I send the file
AT+CFSGFIS=\"audio.amr\"
Here's my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "rs232.h"
char *readFile(char *filename, int *size) {
char *source = NULL;
FILE *fp = fopen(filename, "rb");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { return NULL; }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
if(!source) return NULL;
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { return NULL; }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
free(source);
return NULL;
} else {
source[newLen++] = 0; /* Just to be safe. */
}
*size = bufsize;
}
fclose(fp);
}
return source;
}
int main(int argc, char *argv[])
{
int ret = 0, cport_nr = 2, bdrate=38400;
char data[2000] = {0};
if(RS232_OpenComport(cport_nr, bdrate)) {
printf("Can not open comport\n");
ret = -1;
goto END;
}
int size;
unsigned char *filebuf = readFile("audio.amr", &size);
if (!filebuf) {
ret = -1;
goto END_1;
}
/* Initialization */
RS232_cputs(cport_nr, "AT");
RS232_cputs(cport_nr, "AT+CFSINIT");
sleep(1);
RS232_cputs(cport_nr, "AT+CFSWFILE=\"audio.amr\",0,6694,13000");
/* Wait for CONNECT */
sleep(2);
printf("Sending file of size: %d\n", size);
int i;
for (i = 0; i < size; ++i) {
putchar(filebuf[i]);
RS232_SendByte(cport_nr, filebuf[i]);
}
free(filebuf);
sleep(1);
/* Check if file transferred right */
RS232_cputs(cport_nr, "AT+CFSGFIS=\"audio.amr\"");
END_1:
RS232_CloseComport(cport_nr);
END:
return ret;
}
EDIT 1
Normally, the procedure to send a file to SIM900 using AT commands would be as documented here:
AT+CFSINIT # Initialize flash; Response is OK
AT+CFSWFILE=<filename>,<writeMode>,<fileSize>,<InputTime> # Write file with these parameter; Response is CONNECT; So this is when I start sending the file
Here's where I send the file. If it worked and the sent file size matched the <filesize> sent in the above command, SIM900 must respond with OK, which it doesn't. :(
AT+CFSGFIS=<filename> # Gives the file size on flash. This gives me an error since the file didn't upload correctly.
This leads me to beleive there's something wrong with my program. I'm reading the file in binary mode. And the size reported is exacty the same as I specify in the AT+CFSWFILE=<filename>,<writeMode>,<fileSize>,<InputTime> command.
On Ubuntu Linux I have written a c program based on the Libao example program to open audio wave file and play. It works fine but at the end after finish playing there is crackling high pitch noise. Here is the code which I modified mt libao example. How can I fix it? Please help
#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>
#define BUF_SIZE 4096
int main(int argc, char **argv)
{
ao_device *device;
ao_sample_format format;
int default_driver;
char *buffer;
int buf_size;
int sample;
FILE *fp;
float freq = 440.0;
int i;
/* -- Initialize -- */
fprintf(stderr, "libao example program\n");
ao_initialize();
/* -- Setup for default driver -- */
default_driver = ao_default_driver_id();
memset(&format, 0, sizeof(format));
format.bits = 16;
format.channels = 2;
format.rate = 44100;
format.byte_format = AO_FMT_LITTLE;
/* -- Open driver -- */
// device = ao_open_live(default_driver, &format, NULL /* no options */);
device = ao_open_live(default_driver, &format, NULL /* no options */);
if (device == NULL) {
fprintf(stderr, "Error opening device.\n");
return 1;
}
fp = fopen("nc.wav", "rb");
if (fp == NULL) {
fprintf(stderr, "Unable to open file \n");
return;
}
fseek(fp, 0, SEEK_END);
unsigned long fileLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
//Allocate memory
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(fp);
return;
}
fread(buffer, fileLen, 1, fp);
fclose(fp);
ao_play(device, buffer, buf_size);
/* -- Close and shutdown -- */
ao_close(device);
ao_shutdown();
return (0);
}
The buf_size variable is passed to ao_play without being initialized, and the crackles most likely occur because it is playing past the end of the sample buffer into random memory.
Depending on your compiler settings, the compiler can warn you about uninitialized variables bugs like this (gcc only does it when optimizations are turned on, via the -Wuninitialized or -Wall settings).
i have been trying to decode an MP3 file to pcm, using ffmpeg API, but i keep getting an error
[mp3 # 0x8553020]Header missing
this is the code i use :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP3ON4);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
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 (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (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 */
fwrite(outbuf, 1, out_size, outfile);
}
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);
}
int main(int argc, char **argv)
{
const char *filename;
/* must be called before using avcodec lib */
avcodec_init();
/* register all the codecs */
avcodec_register_all();
audio_decode_example("test.wav", argv[1]);
return 0;
}
when i use the same code to directly play the sound, like this :
if (out_size > 0) {
/* if a frame has been decoded, output it *
play_sound(outbuf, out_size);
}
i have no problem at all with some files, other mp3 files just gives an error without even starting ... is there any ideas ?
PS: this code is from libavcodec/api-example.c , modified as needed
I think i found my answer, the avpkt.data must have a header in front, without any garbage or previous frame bytes, or may be initial mp3 file data (name, gender, year ... etc).
so a little parser must be wrote, this is a useful link for mp3 headers (just search for the correct bytes in within the file, and increase avpkt.data pointer to match):
http://www.mp3-tech.org/programmer/frame_header.html
Use avformat for reading instead of fread(). For example, it can be customized (e.g. for buffering), it can detect and check formats automatically on opening and also has separated probe functions and other format-related stuff. And it works properly with headers. I came to following usage (warning, code can contain errors)
struct FormatCtx {
inline FormatCtx(const char* filename)
: ctx_(avformat_alloc_context()) {
av_init_packet(&p);
if (avformat_open_input(&ctx_, filename, 0, 0) < 0)
abort();
if (avformat_find_stream_info(ctx_, 0) < 0)
abort();
}
inline ~FormatCtx() {
av_free_packet(&p);
}
inline bool read() {
return av_read_frame(ctx_, &p) >= 0;
}
AVFormatContext* ctx_;
AVPacket p;
} formatCtx_;
AVCodec* findCodec(const char* filename) {
AVCodec* codec = formatCtx_.ctx_->audio_codec;
if (codec)
return codec;
codec = avcodec_find_decoder(formatCtx_.ctx_->audio_codec_id);
if (codec)
return codec;
AVOutputFormat* fmt = av_guess_format(0, //const char *short_name,
filename, 0); // const char *mime_type);;
codec = fmt ? avcodec_find_decoder(fmt->audio_codec) : 0;
if (codec)
return codec;
return 0;
}
//*** initialize all stuff ***
AVCodec* codec = findCodec(filename);
if (!codec)
exit(1);
AVCodecContext* c; // class member for me, needed for following reading
int stream_index_; // class member for me, needed for extra stuff
for (size_t i = 0; i < formatCtx_.ctx_->nb_streams; ++i) {
AVCodecContext* tc = formatCtx_.ctx_->streams[i]->codec;
if (tc->codec_type == AVMEDIA_TYPE_AUDIO) {
c = tc;
stream_index_ = i;
break;
}
}
// for example, here we're know track length
l->onDurationDetected(double(formatCtx_.ctx_->streams[stream_index_]->duration)
* av_q2d(formatCtx_.ctx_->streams[stream_index_]->time_base));
if (avcodec_open2(c, codec, &d.d_) < 0)
exit(1);
c->channels = 2;
c->sample_rate = 48000;
c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
c->channel_layout = av_get_default_channel_layout(2);
After that you should basically prepare decoded_frame from TC's example and pass packet used for reading to avcodec_decode_audio4 (instead of avpkt).
I'm trying to decode AAC with FFmpeg native decoder and encountered an error
SSR is not implemeted. Update your FFmpeg version to newest from Git. If the problem still occurs, it mean that your file has a feature which has not implemented.
Function avcodec_decode_audio4() return -1163346256. Is this because of FFmpeg version? I downloaded shared and dev version from here. Is this up to date?
Here is the source code:
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <libavcodec\avcodec.h>
#include <libavformat/avformat.h>
}
// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static void audio_decode_example(const char *outfilename, const char *filename);
int main(int argc, char *argv[]) {
audio_decode_example("D:\\sample.pcm","D:\\sample.m4a");
getch();
return 0;
}
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext * pCodecCtx= NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
av_register_all();
av_init_packet(&avpkt);
printf("Decode audio file %s to %s\n", filename, outfilename);
// Open file to get format context
if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0){
printf("Couldn't open file");
return; // Couldn't open file
}
// Retrieve stream information
if(avformat_find_stream_info(pFormatCtx, NULL)<0){
printf("Couldn't find stream information");
return; // Couldn't find stream information
}
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, filename, 0);
// Find the first audio stream
int audioStream = -1;
int i =0;
for(i=0; i<pFormatCtx->nb_streams; i++) {
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
audioStream=i;
break;
}
}
if(audioStream==-1) {
printf("Didn't find a audio stream");
return; // Didn't find a audio stream
}
// Get a pointer to the codec context for the audio stream
pCodecCtxOrig=pFormatCtx->streams[audioStream]->codec;
// Find the decoder for the audio stream
codec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
if(codec==NULL) {
fprintf(stderr, "Codec not found\n");
return; // Codec not found
}
pCodecCtx = avcodec_alloc_context3(codec);
if (!pCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
return;
}
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
fprintf(stderr, "Couldn't copy codec context");
return; // Error copying codec context
}
/* open it */
if (avcodec_open2(pCodecCtx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return;
}
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(pCodecCtx);
return;
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
int i, ch;
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
fprintf(stderr, "Could not allocate audio frame\n");
return;
}
}
len = avcodec_decode_audio4(pCodecCtx, decoded_frame, &got_frame, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding. len = %d \n",len);
return;
}
if (got_frame) {
/* if a frame has been decoded, output it */
int data_size = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
if (data_size < 0) {
/* This should not occur, checking just for paranoia */
fprintf(stderr, "Failed to calculate data size\n");
return;
}
for (i=0; i < decoded_frame->nb_samples; i++)
for (ch=0; ch < pCodecCtx->channels; ch++)
fwrite(decoded_frame->data[ch] + data_size*i, 1, data_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
avpkt.dts =
avpkt.pts = AV_NOPTS_VALUE;
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);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
av_frame_free(&decoded_frame);
}
I have also read this question: How to decode AAC using avcodec_decode_audio4? but no solution is provided.
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(pCodecCtx);
return;
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
int i, ch;
int got_frame = 0;
Yeah, that's not going to work. You can't dump raw bytes from some random muxing format (potentially mp4) into a decoder and expect it to work. Use av_read_frame() to read individual audio packets from the muxing format, and feed the resulting AVPacket into the decoder using avcodec_decode_audio4(). See e.g. the dranger api tutorial. I know api-example.c uses the above code, but that unfortunately only works for a very limited subset of cases. Also see the detailed description in the API docs.
I'm trying to encode a series of .jpg files into a video using the ffmpeg library, and I can't seem to get the frames to encode. (I have to use the ffmpeg library, and using ffmpeg from a command line is not an option in my case.)
Except for the part where I'm trying to open JPG files as AVFrames, my code is more or less the same thing as found in api-example.c from the ffmpeg library. When I populate the frames as the example does, everything works as expected. In the code below, I fail to encode any frames. Obviously the trouble is related to how I'm opening the JPG files, but I can't figure out what.
I'm opening the image like this:
AVFrame* open_image(const char* imageFileName, int width, int height, long * bufSize)
{
AVFormatContext *pFormatCtx;
if(av_open_input_file(&pFormatCtx, imageFileName, NULL, 0, NULL)!=0)
{
printf("Can't open image file '%s'\n", imageFileName);
return NULL;
}
AVCodecContext *pCodecCtx;
pCodecCtx = pFormatCtx->streams[0]->codec;
pCodecCtx->width = width;
pCodecCtx->height = height;
pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
// Find the decoder for the video stream
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (!pCodec)
{
printf("Codec not found\n");
return NULL;
}
// Open codec
if(avcodec_open(pCodecCtx, pCodec)<0)
{
printf("Could not open codec\n");
return NULL;
}
AVFrame *pFrame = avcodec_alloc_frame();
if (!pFrame)
{
LOGV(TAG, "Can't allocate memory for AVFrame\n");
return NULL;
}
int frameFinished;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height);
// ***
*bufSize = numBytes;
// ***
uint8_t *buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrame, buffer, PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height);
// Read frame
AVPacket packet;
int framesNumber = 0;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index != 0)
continue;
int ret = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (ret > 0)
{
sprintf(buf, "Frame is decoded, size %d", ret);
LOGV(TAG, buf);
pFrame->quality = 4;
return pFrame;
}
else {
// printf("Error [%d] while decoding frame: %s\n", ret, strerror(AVERROR(ret)));
sprintf(buf, "Error %d decoding frame: %s", ret, strerror(AVERROR(ret)));
LOGV(TAG, buf);
}
}
}
...and attempting to encode them like this:
DIR * dir = opendir(path);
int i = 0;
if (dir != NULL) {
for(struct dirent *ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
fflush(stdout);
printf("%s/%s", path, ent->d_name);
LOGV(TAG, filename);
// If not a jpg file, pass it over
const char * ext = strrchr(filename, '.');
if((!ext) || (strcmp(ext, ".jpg"))) {
continue;
}
/*** NOTE: Is this where I've gone wrong? Bufsize is set in open_image based on av_picture_size() */
long bufSize = 0L;
AVFrame * frame = open_image(filename, width, height, &bufSize);
if(frame) {
// This is what it needs to do, and it does not work.
// Causes:
// Wrong format?
// Wrong buffer size?
uint8_t * picBuf = (uint8_t *)malloc(bufSize);
out_size = avcodec_encode_video(c, picBuf, bufSize, frame);
printf("encoding frame %3d (size=%5d)\n", i++, out_size);
/** On the first image, out_size is 0. On the next, it's -1, and fails. */
if(out_size < 0) {
printf("Error encoding frame");
return -6;
}
fwrite(picBuf, 1, bufSize, f);
free(picBuf);
av_free(frame);
}
else {
printf("Couldn't open image");
return -5;
}
}
closedir(dir);
}
else {
printf("Couldn't open directory %s\n", path);
return -4;
}
Could someone point me in the right direction?
What exactly is the error you are getting? Examine the Encoding context after opening it to see it's supported pixel formats, you might have to use sws_scale to convert to a format the encoder supports.