Related
I want to transcode and down/re-sample the audio for output using ffmpeg's libav*/libswresample - I am using ffmpeg's (4.x) transcode_aac.c and resample_audio.c as reference - but the code produces audio with glitches that is clearly not what ffmpeg itself would produce (ie ffmpeg -i foo.wav -ar 22050 foo.m4a)
Based on the ffmpeg examples, to resample audio it appears that I need to set the output AVAudioContext and SwrContext sample_rate to what I desire and ensure the swr_convert() is provided with the correct number of output samples based av_rescale_rnd( swr_delay(), ...) once I have an decoded input audio. I've taken care to ensure all the relevant calculations of samples for output are taken into account in the merged code (below):
open_output_file() - AVCodecContext.sample_rate (avctx variable) set to our target (down sampled) sample_rate
read_decode_convert_and_store() is where the work happens: input audio is decoded to an AVFrame and this input frame is converted before being encoded.
init_converted_samples() and av_samples_alloc() uses the input frame's nb_samples
ADDED: calc the number of output samples via av_rescale_rnd() and swr_delay()
UPDATED: convert_samples() and swr_convert() uses the input frame's samples and our calculated output samples as parameters
However the resulting audio file is produced with audio glitches. Does the community know of any references for how transcode AND resample should be done or what is missing in this example?
/* compile and run:
gcc -I/usr/include/ffmpeg transcode-swr-aac.c -lavformat -lavutil -lavcodec -lswresample -lm
./a.out foo.wav foo.m4a
*/
/*
* Copyright (c) 2013-2018 Andreas Unterweger
*
* This file is part of FFmpeg.
... ...
*
* #example transcode_aac.c
* Convert an input audio file to AAC in an MP4 container using FFmpeg.
* Formats other than MP4 are supported based on the output file extension.
* #author Andreas Unterweger (xxxx#xxxxx.com)
*/
#include <stdio.h>
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/frame.h"
#include "libavutil/opt.h"
#include "libswresample/swresample.h"
#define OUTPUT_BIT_RATE 128000
#define OUTPUT_CHANNELS 2
static int open_input_file(const char *filename,
AVFormatContext **input_format_context,
AVCodecContext **input_codec_context)
{
AVCodecContext *avctx;
const AVCodec *input_codec;
const AVStream *stream;
int error;
if ((error = avformat_open_input(input_format_context, filename, NULL,
NULL)) < 0) {
fprintf(stderr, "Could not open input file '%s' (error '%s')\n",
filename, av_err2str(error));
*input_format_context = NULL;
return error;
}
if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) {
fprintf(stderr, "Could not open find stream info (error '%s')\n",
av_err2str(error));
avformat_close_input(input_format_context);
return error;
}
if ((*input_format_context)->nb_streams != 1) {
fprintf(stderr, "Expected one audio input stream, but found %d\n",
(*input_format_context)->nb_streams);
avformat_close_input(input_format_context);
return AVERROR_EXIT;
}
stream = (*input_format_context)->streams[0];
if (!(input_codec = avcodec_find_decoder(stream->codecpar->codec_id))) {
fprintf(stderr, "Could not find input codec\n");
avformat_close_input(input_format_context);
return AVERROR_EXIT;
}
avctx = avcodec_alloc_context3(input_codec);
if (!avctx) {
fprintf(stderr, "Could not allocate a decoding context\n");
avformat_close_input(input_format_context);
return AVERROR(ENOMEM);
}
/* Initialize the stream parameters with demuxer information. */
error = avcodec_parameters_to_context(avctx, stream->codecpar);
if (error < 0) {
avformat_close_input(input_format_context);
avcodec_free_context(&avctx);
return error;
}
/* Open the decoder for the audio stream to use it later. */
if ((error = avcodec_open2(avctx, input_codec, NULL)) < 0) {
fprintf(stderr, "Could not open input codec (error '%s')\n",
av_err2str(error));
avcodec_free_context(&avctx);
avformat_close_input(input_format_context);
return error;
}
/* Set the packet timebase for the decoder. */
avctx->pkt_timebase = stream->time_base;
/* Save the decoder context for easier access later. */
*input_codec_context = avctx;
return 0;
}
static int open_output_file(const char *filename,
AVCodecContext *input_codec_context,
AVFormatContext **output_format_context,
AVCodecContext **output_codec_context)
{
AVCodecContext *avctx = NULL;
AVIOContext *output_io_context = NULL;
AVStream *stream = NULL;
const AVCodec *output_codec = NULL;
int error;
if ((error = avio_open(&output_io_context, filename,
AVIO_FLAG_WRITE)) < 0) {
fprintf(stderr, "Could not open output file '%s' (error '%s')\n",
filename, av_err2str(error));
return error;
}
if (!(*output_format_context = avformat_alloc_context())) {
fprintf(stderr, "Could not allocate output format context\n");
return AVERROR(ENOMEM);
}
(*output_format_context)->pb = output_io_context;
if (!((*output_format_context)->oformat = av_guess_format(NULL, filename,
NULL))) {
fprintf(stderr, "Could not find output file format\n");
goto cleanup;
}
if (!((*output_format_context)->url = av_strdup(filename))) {
fprintf(stderr, "Could not allocate url.\n");
error = AVERROR(ENOMEM);
goto cleanup;
}
if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) {
fprintf(stderr, "Could not find an AAC encoder.\n");
goto cleanup;
}
/* Create a new audio stream in the output file container. */
if (!(stream = avformat_new_stream(*output_format_context, NULL))) {
fprintf(stderr, "Could not create new stream\n");
error = AVERROR(ENOMEM);
goto cleanup;
}
avctx = avcodec_alloc_context3(output_codec);
if (!avctx) {
fprintf(stderr, "Could not allocate an encoding context\n");
error = AVERROR(ENOMEM);
goto cleanup;
}
/* Set the basic encoder parameters.
* SET OUR DESIRED output sample_rate here
*/
avctx->channels = OUTPUT_CHANNELS;
avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);
// avctx->sample_rate = input_codec_context->sample_rate;
avctx->sample_rate = 22050;
avctx->sample_fmt = output_codec->sample_fmts[0];
avctx->bit_rate = OUTPUT_BIT_RATE;
avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
/* Set the sample rate for the container. */
stream->time_base.den = avctx->sample_rate;
stream->time_base.num = 1;
if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER)
avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) {
fprintf(stderr, "Could not open output codec (error '%s')\n",
av_err2str(error));
goto cleanup;
}
error = avcodec_parameters_from_context(stream->codecpar, avctx);
if (error < 0) {
fprintf(stderr, "Could not initialize stream parameters\n");
goto cleanup;
}
/* Save the encoder context for easier access later. */
*output_codec_context = avctx;
return 0;
cleanup:
avcodec_free_context(&avctx);
avio_closep(&(*output_format_context)->pb);
avformat_free_context(*output_format_context);
*output_format_context = NULL;
return error < 0 ? error : AVERROR_EXIT;
}
/**
* Initialize one data packet for reading or writing.
*/
static int init_packet(AVPacket **packet)
{
if (!(*packet = av_packet_alloc())) {
fprintf(stderr, "Could not allocate packet\n");
return AVERROR(ENOMEM);
}
return 0;
}
static int init_input_frame(AVFrame **frame)
{
if (!(*frame = av_frame_alloc())) {
fprintf(stderr, "Could not allocate input frame\n");
return AVERROR(ENOMEM);
}
return 0;
}
static int init_resampler(AVCodecContext *input_codec_context,
AVCodecContext *output_codec_context,
SwrContext **resample_context)
{
int error;
/**
* create the resample, including ref to the desired output sample rate
*/
*resample_context = swr_alloc_set_opts(NULL,
av_get_default_channel_layout(output_codec_context->channels),
output_codec_context->sample_fmt,
output_codec_context->sample_rate,
av_get_default_channel_layout(input_codec_context->channels),
input_codec_context->sample_fmt,
input_codec_context->sample_rate,
0, NULL);
if (!*resample_context < 0) {
fprintf(stderr, "Could not allocate resample context\n");
return AVERROR(ENOMEM);
}
if ((error = swr_init(*resample_context)) < 0) {
fprintf(stderr, "Could not open resample context\n");
swr_free(resample_context);
return error;
}
return 0;
}
static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context)
{
if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt,
output_codec_context->channels, 1))) {
fprintf(stderr, "Could not allocate FIFO\n");
return AVERROR(ENOMEM);
}
return 0;
}
static int write_output_file_header(AVFormatContext *output_format_context)
{
int error;
if ((error = avformat_write_header(output_format_context, NULL)) < 0) {
fprintf(stderr, "Could not write output file header (error '%s')\n",
av_err2str(error));
return error;
}
return 0;
}
static int decode_audio_frame(AVFrame *frame,
AVFormatContext *input_format_context,
AVCodecContext *input_codec_context,
int *data_present, int *finished)
{
AVPacket *input_packet;
int error;
error = init_packet(&input_packet);
if (error < 0)
return error;
*data_present = 0;
*finished = 0;
if ((error = av_read_frame(input_format_context, input_packet)) < 0) {
if (error == AVERROR_EOF)
*finished = 1;
else {
fprintf(stderr, "Could not read frame (error '%s')\n",
av_err2str(error));
goto cleanup;
}
}
if ((error = avcodec_send_packet(input_codec_context, input_packet)) < 0) {
fprintf(stderr, "Could not send packet for decoding (error '%s')\n",
av_err2str(error));
goto cleanup;
}
error = avcodec_receive_frame(input_codec_context, frame);
if (error == AVERROR(EAGAIN)) {
error = 0;
goto cleanup;
} else if (error == AVERROR_EOF) {
*finished = 1;
error = 0;
goto cleanup;
} else if (error < 0) {
fprintf(stderr, "Could not decode frame (error '%s')\n",
av_err2str(error));
goto cleanup;
} else {
*data_present = 1;
goto cleanup;
}
cleanup:
av_packet_free(&input_packet);
return error;
}
static int init_converted_samples(uint8_t ***converted_input_samples,
AVCodecContext *output_codec_context,
int frame_size)
{
int error;
if (!(*converted_input_samples = calloc(output_codec_context->channels,
sizeof(**converted_input_samples)))) {
fprintf(stderr, "Could not allocate converted input sample pointers\n");
return AVERROR(ENOMEM);
}
if ((error = av_samples_alloc(*converted_input_samples, NULL,
output_codec_context->channels,
frame_size,
output_codec_context->sample_fmt, 0)) < 0) {
fprintf(stderr,
"Could not allocate converted input samples (error '%s')\n",
av_err2str(error));
av_freep(&(*converted_input_samples)[0]);
free(*converted_input_samples);
return error;
}
return 0;
}
static int convert_samples(const uint8_t **input_data, const int input_nb_samples,
uint8_t **converted_data, const int output_nb_samples,
SwrContext *resample_context)
{
int error;
if ((error = swr_convert(resample_context,
converted_data, output_nb_samples,
input_data , input_nb_samples)) < 0) {
fprintf(stderr, "Could not convert input samples (error '%s')\n",
av_err2str(error));
return error;
}
return 0;
}
static int add_samples_to_fifo(AVAudioFifo *fifo,
uint8_t **converted_input_samples,
const int frame_size)
{
int error;
if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) {
fprintf(stderr, "Could not reallocate FIFO\n");
return error;
}
if (av_audio_fifo_write(fifo, (void **)converted_input_samples,
frame_size) < frame_size) {
fprintf(stderr, "Could not write data to FIFO\n");
return AVERROR_EXIT;
}
return 0;
}
static int read_decode_convert_and_store(AVAudioFifo *fifo,
AVFormatContext *input_format_context,
AVCodecContext *input_codec_context,
AVCodecContext *output_codec_context,
SwrContext *resampler_context,
int *finished)
{
AVFrame *input_frame = NULL;
uint8_t **converted_input_samples = NULL;
int data_present;
int ret = AVERROR_EXIT;
if (init_input_frame(&input_frame))
goto cleanup;
if (decode_audio_frame(input_frame, input_format_context,
input_codec_context, &data_present, finished))
goto cleanup;
if (*finished) {
ret = 0;
goto cleanup;
}
if (data_present) {
/* Initialize the temporary storage for the converted input samples. */
if (init_converted_samples(&converted_input_samples, output_codec_context,
input_frame->nb_samples))
goto cleanup;
/* figure out how many samples are required for target sample_rate incl
* any items left in the swr buffer
*/
int output_nb_samples = av_rescale_rnd(
swr_get_delay(resampler_context, input_codec_context->sample_rate) + input_frame->nb_samples,
output_codec_context->sample_rate,
input_codec_context->sample_rate,
AV_ROUND_UP);
/* ignore, just to ensure we've got enough buffer alloc'd for conversion buffer */
av_assert1(input_frame->nb_samples > output_nb_samples);
/* Convert the input samples to the desired output sample format, via swr_convert().
*/
if (convert_samples((const uint8_t**)input_frame->extended_data, input_frame->nb_samples,
converted_input_samples, output_nb_samples,
resampler_context))
goto cleanup;
/* Add the converted input samples to the FIFO buffer for later processing. */
if (add_samples_to_fifo(fifo, converted_input_samples,
output_nb_samples))
goto cleanup;
ret = 0;
}
ret = 0;
cleanup:
if (converted_input_samples) {
av_freep(&converted_input_samples[0]);
free(converted_input_samples);
}
av_frame_free(&input_frame);
return ret;
}
static int init_output_frame(AVFrame **frame,
AVCodecContext *output_codec_context,
int frame_size)
{
int error;
if (!(*frame = av_frame_alloc())) {
fprintf(stderr, "Could not allocate output frame\n");
return AVERROR_EXIT;
}
/* Set the frame's parameters, especially its size and format.
* av_frame_get_buffer needs this to allocate memory for the
* audio samples of the frame.
* Default channel layouts based on the number of channels
* are assumed for simplicity. */
(*frame)->nb_samples = frame_size;
(*frame)->channel_layout = output_codec_context->channel_layout;
(*frame)->format = output_codec_context->sample_fmt;
(*frame)->sample_rate = output_codec_context->sample_rate;
/* Allocate the samples of the created frame. This call will make
* sure that the audio frame can hold as many samples as specified. */
if ((error = av_frame_get_buffer(*frame, 0)) < 0) {
fprintf(stderr, "Could not allocate output frame samples (error '%s')\n",
av_err2str(error));
av_frame_free(frame);
return error;
}
return 0;
}
/* Global timestamp for the audio frames. */
static int64_t pts = 0;
/**
* Encode one frame worth of audio to the output file.
*/
static int encode_audio_frame(AVFrame *frame,
AVFormatContext *output_format_context,
AVCodecContext *output_codec_context,
int *data_present)
{
AVPacket *output_packet;
int error;
error = init_packet(&output_packet);
if (error < 0)
return error;
/* Set a timestamp based on the sample rate for the container. */
if (frame) {
frame->pts = pts;
pts += frame->nb_samples;
}
*data_present = 0;
error = avcodec_send_frame(output_codec_context, frame);
if (error < 0 && error != AVERROR_EOF) {
fprintf(stderr, "Could not send packet for encoding (error '%s')\n",
av_err2str(error));
goto cleanup;
}
error = avcodec_receive_packet(output_codec_context, output_packet);
if (error == AVERROR(EAGAIN)) {
error = 0;
goto cleanup;
} else if (error == AVERROR_EOF) {
error = 0;
goto cleanup;
} else if (error < 0) {
fprintf(stderr, "Could not encode frame (error '%s')\n",
av_err2str(error));
goto cleanup;
} else {
*data_present = 1;
}
/* Write one audio frame from the temporary packet to the output file. */
if (*data_present &&
(error = av_write_frame(output_format_context, output_packet)) < 0) {
fprintf(stderr, "Could not write frame (error '%s')\n",
av_err2str(error));
goto cleanup;
}
cleanup:
av_packet_free(&output_packet);
return error;
}
/**
* Load one audio frame from the FIFO buffer, encode and write it to the
* output file.
*/
static int load_encode_and_write(AVAudioFifo *fifo,
AVFormatContext *output_format_context,
AVCodecContext *output_codec_context)
{
AVFrame *output_frame;
/* Use the maximum number of possible samples per frame.
* If there is less than the maximum possible frame size in the FIFO
* buffer use this number. Otherwise, use the maximum possible frame size. */
const int frame_size = FFMIN(av_audio_fifo_size(fifo),
output_codec_context->frame_size);
int data_written;
if (init_output_frame(&output_frame, output_codec_context, frame_size))
return AVERROR_EXIT;
/* Read as many samples from the FIFO buffer as required to fill the frame.
* The samples are stored in the frame temporarily. */
if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) {
fprintf(stderr, "Could not read data from FIFO\n");
av_frame_free(&output_frame);
return AVERROR_EXIT;
}
/* Encode one frame worth of audio samples. */
if (encode_audio_frame(output_frame, output_format_context,
output_codec_context, &data_written)) {
av_frame_free(&output_frame);
return AVERROR_EXIT;
}
av_frame_free(&output_frame);
return 0;
}
/**
* Write the trailer of the output file container.
*/
static int write_output_file_trailer(AVFormatContext *output_format_context)
{
int error;
if ((error = av_write_trailer(output_format_context)) < 0) {
fprintf(stderr, "Could not write output file trailer (error '%s')\n",
av_err2str(error));
return error;
}
return 0;
}
int main(int argc, char **argv)
{
AVFormatContext *input_format_context = NULL, *output_format_context = NULL;
AVCodecContext *input_codec_context = NULL, *output_codec_context = NULL;
SwrContext *resample_context = NULL;
AVAudioFifo *fifo = NULL;
int ret = AVERROR_EXIT;
if (argc != 3) {
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(1);
}
if (open_input_file(argv[1], &input_format_context,
&input_codec_context))
goto cleanup;
if (open_output_file(argv[2], input_codec_context,
&output_format_context, &output_codec_context))
goto cleanup;
if (init_resampler(input_codec_context, output_codec_context,
&resample_context))
goto cleanup;
if (init_fifo(&fifo, output_codec_context))
goto cleanup;
if (write_output_file_header(output_format_context))
goto cleanup;
while (1) {
/* Use the encoder's desired frame size for processing. */
const int output_frame_size = output_codec_context->frame_size;
int finished = 0;
while (av_audio_fifo_size(fifo) < output_frame_size) {
/* Decode one frame worth of audio samples, convert it to the
* output sample format and put it into the FIFO buffer. */
if (read_decode_convert_and_store(fifo, input_format_context,
input_codec_context,
output_codec_context,
resample_context, &finished))
goto cleanup;
if (finished)
break;
}
while (av_audio_fifo_size(fifo) >= output_frame_size ||
(finished && av_audio_fifo_size(fifo) > 0))
if (load_encode_and_write(fifo, output_format_context,
output_codec_context))
goto cleanup;
if (finished) {
int data_written;
do {
if (encode_audio_frame(NULL, output_format_context,
output_codec_context, &data_written))
goto cleanup;
} while (data_written);
break;
}
}
if (write_output_file_trailer(output_format_context))
goto cleanup;
ret = 0;
cleanup:
if (fifo)
av_audio_fifo_free(fifo);
swr_free(&resample_context);
if (output_codec_context)
avcodec_free_context(&output_codec_context);
if (output_format_context) {
avio_closep(&output_format_context->pb);
avformat_free_context(output_format_context);
}
if (input_codec_context)
avcodec_free_context(&input_codec_context);
if (input_format_context)
avformat_close_input(&input_format_context);
return ret;
}
After going through the ffmpeg/libav mailing list, particularly https://ffmpeg.org/pipermail/libav-user/2017-July/010496.html, I was able to modify the ffmpeg transcode_aac.c example to perform the sample rate conversion.
In the original code, the main loop reads/decode/covert/store in one function before passing the samples to a AVAudioFifo which is used by the encoder.
Some encoders expects a specific number of samples - if you provide less, it appears the encoder pads up to expected and this results in the glitches mentioned in my first attempt.
The key, as per the ffmpeg mailing list, is to buffer / concat the decoded input samples until we have enough samples for at least one frame for the encoder. To do this we split the read/decode from the convert/store with the read/decode data being stored in a new intermediary AVAudioFifo. Once the intermediary fifo has enough samples, they get converted and the output is added to the original fifo.
static int read_decode_and_store(AVAudioFifo *fifo,
AVFormatContext *input_format_context,
AVCodecContext *input_codec_context,
const int audio_stream_idx,
int *finished)
{
AVFrame *input_frame = NULL;
int data_present = 0;
int ret = AVERROR_EXIT;
if (init_input_frame(&input_frame))
goto cleanup;
if (decode_audio_frame(input_frame, input_format_context,
input_codec_context, audio_stream_idx, &data_present, finished))
goto cleanup;
if (*finished) {
ret = 0;
goto cleanup;
}
if (data_present) {
/* Add the converted input samples to the FIFO buffer for later processing. */
if (add_samples_to_fifo(fifo, (uint8_t**)input_frame->extended_data, input_frame->nb_samples))
goto cleanup;
}
ret = 0;
cleanup:
av_frame_free(&input_frame);
return ret;
}
static int load_convert_and_store(AVAudioFifo* output_samples_fifo, const AVFormatContext* output_context, AVCodecContext* output_codec_context, int output_frame_size,
AVAudioFifo* input_samples_fifo, const AVFormatContext* input_context, AVCodecContext* input_codec_context,
SwrContext* resample_context)
{
uint8_t **converted_input_samples = NULL;
int ret = AVERROR_EXIT;
AVFrame *input_frame;
const int frame_size = FFMIN(av_audio_fifo_size(input_samples_fifo),
output_frame_size);
// yes this is init_output_frame
if (init_output_frame(&input_frame, input_codec_context, frame_size))
return AVERROR_EXIT;
if (av_audio_fifo_read(input_samples_fifo, (void **)input_frame->data, frame_size) < frame_size) {
fprintf(stderr, "Could not read data from input samples FIFO");
av_frame_free(&input_frame);
return AVERROR_EXIT;
}
int nb_samples = (output_codec_context->sample_rate == input_codec_context->sample_rate) ?
input_frame->nb_samples :
av_rescale_rnd(swr_get_delay(resample_context, input_codec_context->sample_rate) + input_frame->nb_samples, output_codec_context->sample_rate, input_codec_context->sample_rate, AV_ROUND_UP);
if (init_converted_samples(&converted_input_samples, output_codec_context,
nb_samples))
goto cleanup;
/* **** Modify convert_samples() to return the value from swr_convert() **** */
if ( (nb_samples = convert_samples((const uint8_t**)input_frame->extended_data, input_frame->nb_samples,
converted_input_samples, output_codec_context->frame_size,
resample_context)) < 0)
goto cleanup;
if (add_samples_to_fifo(output_samples_fifo, converted_input_samples, nb_samples))
goto cleanup;
ret = 0;
cleanup:
if (converted_input_samples) {
av_freep(&converted_input_samples[0]);
free(converted_input_samples);
}
av_frame_free(&input_frame);
return ret;
}
int main()
{
...
while (1)
{
const int output_frame_size = output_codec_context->frame_size;
int finished = 0;
/* Re: Resample frame to specified number of samples
* https://ffmpeg.org/pipermail/libav-user/2017-July/010496.html
* Yes, you need to buffer sufficient audio frames to feed to the encoder.
*
* Calculate the number of in samples:
in_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, c->sample_rate) +
out_nb_samples,
in_sample_rate, c->sample_rate, AV_ROUND_DOWN);
then allocate buffers to concatenate the in samples until you have enough
to pass to swr_ctx.
*/
while (av_audio_fifo_size(input_samples_fifo) < output_frame_size) {
if (read_decode_and_store(input_samples_fifo,
input_format_context, input_codec_context,
audio_stream_idx,
&finished))
goto cleanup;
if (finished)
break;
}
while (av_audio_fifo_size(input_samples_fifo) >= output_frame_size ||
(finished && av_audio_fifo_size(input_samples_fifo) > 0)) {
/* take all input samples and convert them before handing off to encoder
*/
if (load_convert_and_store(fifo,
output_format_context, output_codec_context, output_frame_size,
input_samples_fifo, input_format_context, input_codec_context,
resample_context))
goto cleanup;
}
}
/* If we have enough samples for the encoder, we encode them.
* At the end of the file, we pass the remaining samples to
* the encoder. */
.... // existing code
}
I'm trying to develop a simple audio program that runs on a ADSL router. I found two GPL sources for other routers that have the same chips and I'm able to build kernel and rootfs. I already add ALSA support to the kernel and successfully deployed to the router.
Now I'm trying to get my program to work. Using a usb sound card, the first thing that I'm doing is to passthrough capture signal to the playback and measure the latency.
I already remove all jitter that was present but I can't get a better latency that 1 second (it's a lot of latency). I'm initializing the device with 128 frames of buffer and 1 frame for period size, and latency is always 1 second. I'm using only 1 channel and a rate of 44100, but also tested with a rate of 8000hz and the latency is the same
I already tried setting another priority to the running thread and tested a lot of combinations of hw params, but never could get minor latency than that.
I checked the cpu and memory while my program is running and there is a lot of free resources. I removed many services of the system like telnet, samba and other programs that could interfere with my program.
An interesting point is that when my program only set the playback device and play some pcm file, there is no latency (right after I start the program, the sound is played correctly).
Linux kernel version is v2.6.22.15. Alsa driver is 1.0.14. I tried a cheap usb sound card, a Zoom h1 recorder (that works as usb card) and a Presonus 22vsl audio interface, always the same latency.
The CPU is a Ralink rt63365, it has 4 cores and it seems to run at 400hz aprox.
I don't know what else to try. What kind of test could I do to detect where the latency problem is generated?
Edit
I forget to mention that I run the same program with all the cards mentioned but in my PC (kernel version > 5, with the respective alsa version) and the program works perfectly, there is no notable latency.
Main functions of my program:
void setscheduler(void)
{
struct sched_param sched_param;
if (sched_getparam(0, &sched_param) < 0) {
printf("Scheduler getparam failed...\n");
return;
}
sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority);
fflush(stdout);
return;
}
printf("!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority);
}
int setup_alsa_handle(snd_pcm_t *handle, snd_pcm_stream_t stream)
{
int err = 0;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_access(handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_format(handle, hw_params, AUDIO_FORMAT)) < 0)
{
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err));
exit(1);
}
unsigned int rate = SAMPLE_RATE;
if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0)) <
0)
{
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err));
exit(1);
}
int dir;
snd_pcm_uframes_t period_size = PERIOD_SIZE_IN_FRAMES;
if ((err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, &dir)) <
0)
{
fprintf(stderr, "cannot set period size (%s)\n", snd_strerror(err));
exit(1);
}
int channels;
if (stream == SND_PCM_STREAM_CAPTURE)
{
channels = CAPTURE_CHANNELS;
}
else
{
channels = PLAYBACK_CHANNELS;
}
if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0)
{
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
exit(1);
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_sw_params_malloc(&sw_params)) < 0) {
fprintf(stderr, "cannot allocate software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_current(handle, sw_params)) < 0) {
fprintf(stderr, "cannot initialize software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_avail_min(handle, sw_params, FRAMES_PER_BUFFER)) < 0) {
fprintf(stderr, "cannot set minimum available count(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, 0U)) < 0) {
fprintf(stderr, "cannot set start mode(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params(handle, sw_params)) < 0) {
fprintf(stderr, "cannot set software parameters(%s)\n",
snd_strerror(err));
return err;
}
return 0;
}
void start_stream(snd_pcm_t *_playback_handle, snd_pcm_t *_capture_handle,
void (*stream_callback)(const void *, void *, unsigned long,
void *),
void (*controls_callback)(void *), void *data)
{
audio_sample *in_buffer;
audio_sample *out_buffer;
FILE *fout = NULL;
int in_result = 0;
int out_result = 0;
int temp_n = 0;
int buffer_frames = FRAMES_PER_BUFFER;
int frame_size_in_bytes = snd_pcm_format_width(AUDIO_FORMAT) / 8;
int in_buffer_frames = buffer_frames * CAPTURE_CHANNELS;
in_buffer = (audio_sample *)malloc(in_buffer_frames * frame_size_in_bytes);
int out_buffer_frames = buffer_frames * PLAYBACK_CHANNELS;
out_buffer = (audio_sample *)malloc(out_buffer_frames * frame_size_in_bytes);
memset(in_buffer, SAMPLE_SILENCE, in_buffer_frames * frame_size_in_bytes);
memset(out_buffer, SAMPLE_SILENCE, out_buffer_frames * frame_size_in_bytes);
int err;
while (1)
{
int avail;
if ((err = snd_pcm_wait(_playback_handle, 1000)) < 0) {
fprintf(stderr, "poll failed(%s)\n", strerror(errno));
break;
}
avail = snd_pcm_avail_update(_capture_handle);
fprintf(stderr, "1 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_readi(_capture_handle, in_buffer, avail);
}
avail = snd_pcm_avail_update(_playback_handle);
fprintf(stderr, "2 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_writei(_playback_handle, in_buffer, avail);
}
}
}
/**
* Main
*/
int main(int argc, char *argv[])
{
setscheduler();
if ((err = snd_pcm_open(&capture_handle, CAPTURE_AUDIO_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", CAPTURE_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(capture_handle, SND_PCM_STREAM_CAPTURE);
// Init playback device
if ((err = snd_pcm_open(&playback_handle, PLAYBACK_AUDIO_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", PLAYBACK_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(playback_handle, SND_PCM_STREAM_PLAYBACK);
if ((err = snd_pcm_start(capture_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_prepare(playback_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
// Start stream
start_stream(playback_handle, capture_handle, audio_processing_callback, controls_callback, &data, write_to_file, read_from_file);
return 0;
}
I am using this code to setup a socket to detect a network error:
int socket_keepalive(int s, int ktime, int kinterval, int kprobes) {
int enable = 1;
if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(int)) < 0) {
printf("setsockopt SO_KEEPALIVE failed (%s)\n", strerror(errno));
return -1;
}
if(setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, &ktime, sizeof(int) < 0)) {
printf("setsockopt TCP_KEEPIDLE failed\n");
perror("SO_KEEPALIVE: ");
return -1;
}
if(setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, &kinterval, sizeof(int) < 0)) {
printf("setsockopt TCP_KEEPINTVL failed\n");
perror("TCP_KEEPINTVL: ");
return -1;
}
if(setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, &kprobes, sizeof(int) < 0)) {
printf("setsockopt TCP_KEEPCNT failed\n");
perror("TCP_KEEPCNT: ");
return -1;
}
return 0;
}
I am calling the above function like this:
socket_keepalive(sock, 30, 10, 1);
I expect the socket to be disconnected after 40 seconds after a network error. However, it takes almost 170 seconds after a network error on the remote side.
Any idea what I am doing wrong?
We are using Linux-2.6.28 and 2 Gb NAND Flash in our system ; After some amount of power cycle tests we are observing the following errors :
Volume operational found at volume id 3
read 21966848 bytes from volume 3 to 80400000(buf address)
UBI error: ubi_io_read: error -77 while reading 126976 bytes from PEB 1074:4096, read 126976 bytes
UBI: force data checking
UBI error: ubi_io_read: error -77 while reading 126976 bytes from PEB 1074:4096, read 126976 bytes
UBI warning: ubi_eba_read_leb: CRC error: calculated 0xa7cab743, must be 0x15716fce
read err ffffffb3
These errors are not hardware errors as if we remove the offending partition, we are able to boot the hardware fine; Maybe UBIFS is not correcting the bad UBI block.
Any UBI patches have been added in the latest kernels to address this issue ? Thanks.
The error printed is a UBI error. Lets look at the source near line 177,
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read);
So, error '-77' (normally -EBADFD) was returned from the NAND flash driver when trying to read the 'physical erase block' #1074 at offset 4096 (2nd page for 2k pages). UBI include volume management pages which are typically located at the beginning of a physical erase block (PEB for short).
Note that the latest mainline of io.c has the following comment and code,
/*
* Deliberately corrupt the buffer to improve robustness. Indeed, if we
* do not do this, the following may happen:
* 1. The buffer contains data from previous operation, e.g., read from
* another PEB previously. The data looks like expected, e.g., if we
* just do not read anything and return - the caller would not
* notice this. E.g., if we are reading a VID header, the buffer may
* contain a valid VID header from another PEB.
* 2. The driver is buggy and returns us success or -EBADMSG or
* -EUCLEAN, but it does not actually put any data to the buffer.
*
* This may confuse UBI or upper layers - they may think the buffer
* contains valid data while in fact it is just old data. This is
* especially possible because UBI (and UBIFS) relies on CRC, and
* treats data as correct even in case of ECC errors if the CRC is
* correct.
*
* Try to prevent this situation by changing the first byte of the
* buffer.
*/
*((uint8_t *)buf) ^= 0xFF;
The following code can be used to process a UBI/UbiFS dump and look for abnormalities,
/* -*- mode: c; compile-command: "gcc -Wall -g -o parse_ubi parse_ubi.c"; -*- */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define __packed __attribute__((packed))
#include "ubi-media.h"
#define bswap16 be16toh
#define bswap32 be32toh
#define bswap64 be64toh
static int dump_vid = 0;
#define CRCPOLY_LE 0xedb88320
static unsigned int crc32(unsigned int crc, void const *_p, size_t len)
{
unsigned char const *p = _p;
int i;
while (len--) {
crc ^= *p++;
for (i = 0; i < 8; i++)
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
}
return crc;
}
#define ALEN(a) (sizeof(a)/sizeof(a[0]))
static void print_ec(struct ubi_ec_hdr *ec)
{
if(ec->version != UBI_VERSION || ec->magic != UBI_EC_HDR_MAGIC) {
printf(" Magic: %x\n", ec->magic);
printf(" Version: %d\n", (int)ec->version);
printf(" EC: %llx\n", ec->ec);
printf(" VID offset: %x\n", ec->vid_hdr_offset);
printf(" Data offset: %x\n", ec->data_offset);
printf(" Image seq: %x\n", ec->image_seq);
exit(-1);
}
}
static void read_ec(int fd, struct ubi_ec_hdr *ec)
{
int rval = read(fd, ec,sizeof(*ec));
if(rval == sizeof(*ec)) {
unsigned int crc;
crc = crc32(UBI_CRC32_INIT, ec, UBI_EC_HDR_SIZE_CRC);
ec->magic = bswap32(ec->magic);
ec->vid_hdr_offset = bswap32(ec->vid_hdr_offset);
ec->data_offset = bswap32(ec->data_offset);
ec->image_seq = bswap32(ec->image_seq);
ec->hdr_crc = bswap32(ec->hdr_crc);
ec->ec = bswap64(ec->ec);
if(crc != ec->hdr_crc)
printf("EC CRC: %x/%x\n", crc, ec->hdr_crc);
} else
memset(ec, 0, sizeof(*ec));
}
static void print_vid(int vid_num, struct ubi_vid_hdr *vid)
{
if(vid->magic != UBI_VID_HDR_MAGIC)
printf(" Magic: %x\n", vid->magic);
if(vid->version != UBI_VERSION)
printf(" Version: %d\n", (int)vid->version);
if(!dump_vid) return;
printf("VID %d\n", vid_num);
/* This is usually the same. */
if(vid->vol_id >= UBI_INTERNAL_VOL_START)
printf("Internal vol_id: %d\n", vid->vol_id - UBI_INTERNAL_VOL_START);
if(vid->vol_type != UBI_VID_DYNAMIC)
printf(" vol_type: %s\n",
vid->vol_type == UBI_VID_DYNAMIC ? "dynamic" : "static");
if(vid->used_ebs)
printf(" used_ebs: %d\n", vid->used_ebs);
if(vid->data_pad)
printf(" data_pad: %d\n", vid->data_pad);
if((vid->copy_flag != 1 && vid->data_size) ||
(vid->copy_flag == 0 && vid->data_size))
printf(" copy_flag: %d\n", (int)vid->copy_flag);
printf(" lnum: %d\n", vid->lnum);
if(vid->compat) {
const char *compat[] = {
[UBI_COMPAT_DELETE] = "delete",
[UBI_COMPAT_RO] = "ro",
[UBI_COMPAT_PRESERVE] = "preserve",
[UBI_COMPAT_REJECT] = "reject"
};
printf(" compat: %s\n", compat[vid->compat]);
}
printf(" data_size: %d\n", vid->data_size);
/* printf(" data_crc: %x\n", vid->data_crc); */
printf(" hdr_crc: %x\n", vid->hdr_crc);
printf(" sqnum: %lld\n", vid->sqnum);
}
static int read_vid(int fd, struct ubi_vid_hdr *vid)
{
int rval = read(fd, vid,sizeof(*vid));
if(rval == sizeof(*vid)) {
unsigned int crc;
crc = crc32(UBI_CRC32_INIT, vid, UBI_EC_HDR_SIZE_CRC);
vid->magic = bswap32(vid->magic);
vid->vol_id = bswap32(vid->vol_id);
vid->lnum = bswap32(vid->lnum);
vid->data_size = bswap32(vid->data_size);
vid->used_ebs = bswap32(vid->used_ebs);
vid->data_pad = bswap32(vid->data_pad);
vid->data_crc = bswap32(vid->data_crc);
vid->hdr_crc = bswap32(vid->hdr_crc);
vid->sqnum = bswap64(vid->sqnum);
if(crc != vid->hdr_crc && vid->magic == UBI_VID_HDR_MAGIC)
printf("VID CRC: %x/%x\n", crc, vid->hdr_crc);
} else
memset(vid, 0, sizeof(*vid));
return rval;
}
static void print_vtbl(struct ubi_vtbl_record *vtbl)
{
printf(" Found vtbl [%d] %s\n", vtbl->name_len, vtbl->name);
printf(" Reserved PEBs: %d\n", vtbl->reserved_pebs);
printf(" Align: %d\n", vtbl->alignment);
printf(" Pad: %d\n", vtbl->data_pad);
if(vtbl->vol_type != UBI_VID_DYNAMIC)
printf(" vol_type: %s\n",
vtbl->vol_type == UBI_VID_DYNAMIC ? "dynamic" : "static");
printf(" Update: %d\n", vtbl->upd_marker);
printf(" Flags: %d\n", (int)vtbl->flags);
}
static void read_vtbl(int fd, struct ubi_vtbl_record *vtbl)
{
int rval = read(fd, vtbl, sizeof(*vtbl));
if(rval == sizeof(*vtbl)) {
vtbl->reserved_pebs = bswap32(vtbl->reserved_pebs);
vtbl->alignment = bswap32(vtbl->alignment);
vtbl->data_pad = bswap32(vtbl->data_pad);
vtbl->crc = bswap32(vtbl->crc);
vtbl->name_len = bswap16(vtbl->name_len);
} else
memset(vtbl, 0, sizeof(*vtbl));
}
static void print_fm_sb(struct ubi_fm_sb *fm_sb)
{
int i;
if(fm_sb->magic != UBI_FM_SB_MAGIC)
printf(" Magic: %x\n", fm_sb->magic);
if(fm_sb->version != UBI_VERSION)
printf(" Version: %d\n", (int)fm_sb->version);
printf(" data_crc: %x\n", fm_sb->data_crc);
printf(" used_blocks: %x\n", fm_sb->used_blocks);
for(i = 0; i < fm_sb->used_blocks; i++)
printf(" block_loc[%d]: %d\n", i, fm_sb->block_loc[i]);
for(i=0; i < fm_sb->used_blocks; i++)
printf(" block_ec[%d]: %d\n", i, fm_sb->block_ec[i]);
printf(" sqnum: %lld\n", fm_sb->sqnum);
}
static void read_fm_sb(int fd, struct ubi_fm_sb *fm_sb)
{
int rval = read(fd, fm_sb, sizeof(*fm_sb));
if(rval == sizeof(*fm_sb)) {
int i;
fm_sb->magic = bswap32(fm_sb->magic);
fm_sb->data_crc = bswap32(fm_sb->data_crc);
fm_sb->used_blocks = bswap32(fm_sb->used_blocks);
for(i=0; i < UBI_FM_MAX_BLOCKS; i++)
fm_sb->block_loc[i] = bswap32(fm_sb->block_loc[i]);
for(i=0; i < UBI_FM_MAX_BLOCKS; i++)
fm_sb->block_ec[i] = bswap32(fm_sb->block_ec[i]);
fm_sb->sqnum = bswap64(fm_sb->sqnum);
} else
memset(fm_sb, 0, sizeof(*fm_sb));
}
/* Set logical block at physical. */
static int eba_map[1920];
static int pba_map[1920];
static void usage(char *name)
{
printf("Usage: %s -b [erase block size] -e -v <ubi file> \n", name);
printf("Where,\n -e is dump the logic to physical block map.\n");
printf(" -v is dump the VID headers.\n");
printf(" -b [size] sets the erase block size (flash dependent).\n");
}
typedef struct fastmap {
struct ubi_fm_sb fm_sb;
struct ubi_fm_hdr hdr;
struct ubi_fm_scan_pool pool1;
struct ubi_fm_scan_pool pool2;
/* Free, Used, Scrub and Erase */
struct ubi_fm_ec ec[0];
/* ... */
/* struct ubi_fm_volhdr vol; */
/* struct ubi_fm_eba eba[0]; */
} fastmap;
int main (int argc, char *argv[])
{
int fd, i, erase_block = 0, eba_flag = 0;
int c;
struct ubi_ec_hdr ec;
struct ubi_vid_hdr vid;
int erase_size = 0x20000;
int leb_size;
off_t cur_ec = 0;
int vidless_blocks = 0;
while ((c = getopt (argc, argv, "hveb:")) != -1)
switch (c)
{
case 'h': /* Help */
usage(argv[0]);
goto out;
case 'b':
erase_size = atoi(optarg);
break;
case 'e':
eba_flag = 1;
break;
case 'v':
dump_vid = 1;
break;
case '?':
if (optopt == 'b')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
goto out;
}
if(optind >= argc) {
usage(argv[0]);
goto out;
}
fd = open(argv[optind], O_RDONLY);
if(fd < 0) {
printf("Bad file: %s\n", argv[1]);
goto out;
}
memset(eba_map, -1, sizeof(eba_map));
memset(pba_map, -1, sizeof(pba_map));
/* Process each 'erase block'. */
read_ec(fd,&ec);
while(ec.magic == UBI_EC_HDR_MAGIC) {
leb_size = erase_size - ec.data_offset;
print_ec(&ec);
/* VID present? */
if(lseek(fd, ec.vid_hdr_offset-sizeof(ec), SEEK_CUR) == -1) {
printf("Seek error: %s\n", argv[1]);
goto out;
}
if(read_vid(fd,&vid) != sizeof(vid)) {
printf("File too small: %s\n", argv[1]);
goto out;
}
if(vid.magic == UBI_VID_HDR_MAGIC) {
print_vid(erase_block, &vid);
if(vid.vol_id == 3) {
if(eba_map[vid.lnum] != -1)
printf("EBA dup: %d %d\n", eba_map[vid.lnum], erase_block);
eba_map[vid.lnum] = erase_block;
}
pba_map[erase_block] = vid.lnum;
/* Read volume table. */
if(vid.vol_id == UBI_INTERNAL_VOL_START) {
/* Seek to PEB data offset. */
if(lseek(fd,
ec.data_offset - ec.vid_hdr_offset - sizeof(vid),
SEEK_CUR) == -1)
printf("Seek error: %s\n", argv[1]);
else {
int i;
struct ubi_vtbl_record vtbl;
for(i = 0; i < UBI_MAX_VOLUMES; i++) {
read_vtbl(fd, &vtbl);
if(vtbl.reserved_pebs ||
vtbl.name_len ||
strcmp((char*)vtbl.name, "") != 0) {
printf("VTBL %d\n", i);
print_vtbl(&vtbl);
}
}
}
} else if(vid.vol_id == UBI_FM_SB_VOLUME_ID) {
printf("Found Fastmap super block #PEB %d.\n", erase_block);
if(lseek(fd,
ec.data_offset - ec.vid_hdr_offset - sizeof(vid),
SEEK_CUR) == -1)
printf("Seek error: %s\n", argv[1]);
else {
void *data = alloca(leb_size);
struct ubi_fm_sb *fm_sb = data;
read_fm_sb(fd, data);
print_fm_sb(fm_sb);
}
} else if(vid.vol_id == UBI_FM_DATA_VOLUME_ID) {
printf("Found Fastmap data block #PEB %d.\n", erase_block);
printf("UNSUPPORTED!!!\n");
}
} else if(vid.magic != 0xffffffff){
printf("VID %d corrupt! %x\n", erase_block, vid.magic);
} else {
vidless_blocks++;
}
erase_block++;
cur_ec += erase_size;
cur_ec = lseek(fd, cur_ec, SEEK_SET);
/* Process Erase counter. */
read_ec(fd,&ec);
}
printf("Found %d vidless (free) blocks.\n", vidless_blocks);
if(eba_flag) {
printf("Logical to physical.\n");
for(i = 0; i < ALEN(eba_map); i+=8)
printf("%4d: %4d %4d %4d %4d %4d %4d %4d %4d"
" %4d %4d %4d %4d %4d %4d %4d %4d\n", i,
eba_map[i], eba_map[i+1],
eba_map[i+2], eba_map[i+3],
eba_map[i+4], eba_map[i+5],
eba_map[i+6], eba_map[i+7],
eba_map[i+8], eba_map[i+9],
eba_map[i+10], eba_map[i+11],
eba_map[i+12], eba_map[i+13],
eba_map[i+14], eba_map[i+15]);
printf("Physical to logical.\n");
for(i = 0; i < ALEN(pba_map); i+=8)
printf("%4d: %4d %4d %4d %4d %4d %4d %4d %4d"
" %4d %4d %4d %4d %4d %4d %4d %4d\n", i,
pba_map[i], pba_map[i+1],
pba_map[i+2], pba_map[i+3],
pba_map[i+4], pba_map[i+5],
pba_map[i+6], pba_map[i+7],
pba_map[i+8], pba_map[i+9],
pba_map[i+10], pba_map[i+11],
pba_map[i+12], pba_map[i+13],
pba_map[i+14], pba_map[i+15]);
}
out:
return 0;
}
To build copy ubi-media.h from the UBI directory and run gcc -Wall -g -o parse_ubi parse_ubi.c. The code probably has issues on big-endian platforms; it is also not test with 2.6.28 but I believe it should work as the UBI structures shouldn't change. You may have to remove some fastmap code, if it doesn't compile. The code should give some indication on what is wrong with PEB#1074. Make a copy of the partition when failing and use the code above to analyze the UBI layer.
It is quite possible that the MTD driver does something abnormal which prevents UBI from attaching to an MTD partition. This in-turn prevents UbiFS from mounting. If you know what MTD Nand flash controller is being used, it would help others determine where the issue is.
It can be caused by MTD bugs and/or hardware bugs or UBI/UbiFS issues. If it is UBI/UbiFs, there are backport trees and newer 3.0. You can try to steal the patches from 2.6.32; after applying all, add the 3.0.
Again, the issue can be the MTD driver. Grab MTD changes for your particular CPU/SOCs NAND flash controller. I do this from the mainline; some changes are bug fixes and others infra-structure. You have to look at each patch individually
I want to read and write over Wanpipe driver (a network device driver for Sangoma cards) via socket programming but i get this message error: "resource temporarily unavailable". The card is working and i see it send and receive packets in ifconfig. I have included my code and would be very pleased if somebody help me in this.
A related question: I set the socket to blocking mode but the recv message does not block? how could i block the recv?
int main(void)
{
int sd;
int buflen=WP_HEADER + MAX_PACKET;
char buf[buflen];
struct wan_sockaddr_ll sa;
sd = socket(AF_WANPIPE, SOCK_RAW,0);
if (sd < 0) /* if socket failed to initialize, exit */
{
perror("Error Creating Socket");
exit(1);
}
printf("Socket Descriptor:%d\n",sd);
memset(&sa,0,sizeof(struct wan_sockaddr_ll));
strncpy((char*)sa.sll_card,"wanpipe1",sizeof(sa.sl l_card));
strncpy((char*)sa.sll_device,"w1g1",sizeof(sa.sll_ device));
sa.sll_protocol = htons(PVC_PROT);
sa.sll_family = AF_WANPIPE;
if(bind(sd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
perror("error bind failed");
close(sd);
exit(1);
}
int data=0;
int ret=ioctl(sd,FIONBIO,&data);
if (ret < 0)
{
perror("ioctl error!");
close(sd);
return 1;
}
fd_set read_fds;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(sd,&read_fds);
if(select(sd+1, &read_fds, NULL, NULL, &timeout) < 0)
{
perror("select() error!");
exit(1);
}
if (FD_ISSET(sd,&read_fds))
printf("There is data for reading\n");
else
printf("There is no data for reading\n");*/
// MSG_WAITALL | MSG_PEEK | MSG_OOB
int r=recv(sd,buf,buflen,0);
if (r < 0)
{
perror("Wanpipe raw socket reading");
close(sd);
exit(1);
}
printf("\nNumber of bytes read into the buffer: %d",r);
printf("\nThe read buffer: ");
puts(buf);
close(sd);
}
thank you in advance.