FFMPEG - Encode a .wav file to G711 - c

My question is the following: how to encode a .wav file to G.711/PCM A-law?
I tried to edit this example file, but I got an EINVAL error when tried to call av_frame_get_buffer(frame, 0) with frame->nb_samples = c->frame_size which is 0 (I think this is the problem) because of pcm.c:37 (at least I think because of it).
So with which parameters allocate an audio data buffer by myself if av_frame_get_buffer() doesn't do this for me and how to use it?
Thanks for reply!
EDIT:
My code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{
const enum AVSampleFormat *p = codec->sample_fmts;
while (*p != AV_SAMPLE_FMT_NONE) {
if (*p == sample_fmt)
return 1;
p++;
}
return 0;
}
/* just pick the highest supported samplerate */
static int select_sample_rate(const AVCodec *codec)
{
const int *p;
int best_samplerate = 0;
if (!codec->supported_samplerates)
return 44100;
p = codec->supported_samplerates;
while (*p) {
if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
best_samplerate = *p;
p++;
}
return best_samplerate;
}
/* select layout with the highest channel count */
static int select_channel_layout(const AVCodec *codec)
{
const uint64_t *p;
uint64_t best_ch_layout = 0;
int best_nb_channels = 0;
if (!codec->channel_layouts)
return AV_CH_LAYOUT_STEREO;
p = codec->channel_layouts;
while (*p) {
int nb_channels = av_get_channel_layout_nb_channels(*p);
if (nb_channels > best_nb_channels) {
best_ch_layout = *p;
best_nb_channels = nb_channels;
}
p++;
}
return best_ch_layout;
}
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
FILE *output)
{
int ret;
/* send the frame for encoding */
ret = avcodec_send_frame(ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending the frame to the encoder\n");
exit(1);
}
/* read all the available output packets (in general there may be any
* number of them */
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error encoding audio frame\n");
exit(1);
}
fwrite(pkt->data, 1, pkt->size, output);
av_packet_unref(pkt);
}
}
int main(int argc, char **argv)
{
const char *filename;
const AVCodec *codec;
AVCodecContext *c = NULL;
AVFrame *frame;
AVPacket *pkt;
int i, j, k, ret;
FILE *f;
uint16_t *samples;
float t, tincr;
if (argc <= 1)
{
fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
return 0;
}
filename = argv[1];
codec = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c)
{
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
c->bit_rate = 128000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
if (!check_sample_fmt(codec, c->sample_fmt))
{
fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(c->sample_fmt));
exit(1);
}
c->sample_rate = select_sample_rate(codec);
c->channel_layout = select_channel_layout(codec);
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
if (avcodec_open2(c, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f)
{
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "Could not allocate the packet\n");
exit(1);
}
frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
frame->nb_samples = c->frame_size;
frame->format = c->sample_fmt;
frame->channel_layout = c->channel_layout;
// ERROR Here
ret = av_frame_get_buffer(frame, 0);
if (ret < 0)
{
fprintf(stderr, "Could not allocate audio data buffers\n");
exit(1);
}
t = 0;
tincr = 2 * M_PI * 440.0 / c->sample_rate;
for (i = 0; i < 200; i++)
{
ret = av_frame_make_writable(frame);
if (ret < 0)
{
exit(1);
}
samples = (uint16_t*)frame->data[0];
for (j = 0; j < c->frame_size; j++)
{
samples[2*j] = (int)(sin(t)*10000);
for (k = 1; k < c->channels; k++)
{
samples[2*j + k] = samples[2*j];
}
t += tincr;
}
encode(c, frame, pkt, f);
}
encode(c, NULL, pkt, f);
fclose(f);
av_frame_free(&frame);
av_packet_free(&pkt);
avcodec_free_context(&c);
return 0;
}

Related

H264 codec encode, decode and write to file

I try to use ffmpeg and h264 codec to translate the video in realtime. But at the state of decoding encoded frame, I get some "bad" image.
Init encoder and decoder:
VCSession *vc_new_x264(Logger *log, ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data,
VCSession *vc)
{
// ------ ffmpeg encoder ------
AVCodec *codec2 = NULL;
vc->h264_encoder_ctx = NULL;//AVCodecContext type
codec2 = NULL;
avcodec_register_all();
codec2 = avcodec_find_encoder(AV_CODEC_ID_H264);
if (codec2 == NULL)
{
LOGGER_WARNING(log, "h264: not find encoder");
}
vc->h264_encoder_ctx = avcodec_alloc_context3(codec2);
vc->h264_out_pic2 = av_packet_alloc();
vc->h264_encoder_ctx->bit_rate = 10 *1000 * 1000;
vc->h264_encoder_ctx->width = 800;
vc->h264_encoder_ctx->height = 600;
vc->h264_enc_width = vc->h264_encoder_ctx->width;
vc->h264_enc_height = vc->h264_encoder_ctx->height;
vc->h264_encoder_ctx->time_base = (AVRational) {
1, 30
};
vc->h264_encoder_ctx->gop_size = 30;
vc->h264_encoder_ctx->max_b_frames = 1;
vc->h264_encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
av_opt_set(vc->h264_encoder_ctx->priv_data, "preset", "veryfast", 0);
av_opt_set(vc->h264_encoder_ctx->priv_data, "annex_b", "1", 0);
av_opt_set(vc->h264_encoder_ctx->priv_data, "repeat_headers", "1", 0);
av_opt_set(vc->h264_encoder_ctx->priv_data, "tune", "zerolatency", 0);
av_opt_set_int(vc->h264_encoder_ctx->priv_data, "zerolatency", 1, 0);
vc->h264_encoder_ctx->time_base.num = 1;
vc->h264_encoder_ctx->time_base.den = 1000;
vc->h264_encoder_ctx->framerate = (AVRational) {
1000, 40
};
AVDictionary *opts = NULL;
if (avcodec_open2(vc->h264_encoder_ctx, codec2, &opts) < 0) {
LOGGER_ERROR(log, "could not open codec H264 on encoder");
}
av_dict_free(&opts);
AVCodec *codec = NULL;
vc->h264_decoder_ctx = NULL;// AVCodecContext - type
codec = NULL;
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
LOGGER_WARNING(log, "codec not found H264 on decoder");
}
vc->h264_decoder_ctx = avcodec_alloc_context3(codec);
if (codec->capabilities & AV_CODEC_CAP_TRUNCATED) {
vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
}
if (codec->capabilities & AV_CODEC_FLAG_LOW_DELAY) {
vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
}
vc->h264_decoder_ctx->flags |= AV_CODEC_FLAG2_SHOW_ALL;
vc->h264_decoder_ctx->refcounted_frames = 0;
vc->h264_decoder_ctx->delay = 0;
vc->h264_decoder_ctx->sw_pix_fmt = AV_PIX_FMT_YUV420P;
av_opt_set_int(vc->h264_decoder_ctx->priv_data, "delay", 0, AV_OPT_SEARCH_CHILDREN);
vc->h264_decoder_ctx->time_base = (AVRational) {
40, 1000
};
vc->h264_decoder_ctx->framerate = (AVRational) {
1000, 40
};
if (avcodec_open2(vc->h264_decoder_ctx, codec, NULL) < 0) {
LOGGER_WARNING(log, "could not open codec H264 on decoder");
}
vc->h264_decoder_ctx->refcounted_frames = 0;
return vc;
}
Encoding (in this function i encode frame and for debugging decode and save him in file):
uint32_t encode_frame_h264_p(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height,
const uint8_t *y,
const uint8_t *u, const uint8_t *v, ToxAVCall *call,
uint64_t *video_frame_record_timestamp,
int vpx_encode_flags,
x264_nal_t **nal,
int *i_frame_size)
{
AVFrame *frame;
int ret;
uint32_t result = 1;
frame = av_frame_alloc();
frame->format = call->video->h264_encoder_ctx->pix_fmt;
frame->width = width;
frame->height = height;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0) {
LOGGER_ERROR(av->m->log, "av_frame_get_buffer:Could not allocate the video frame data");
}
/* make sure the frame data is writable */
ret = av_frame_make_writable(frame);
if (ret < 0) {
LOGGER_ERROR(av->m->log, "av_frame_make_writable:ERROR");
}
frame->pts = (int64_t)(*video_frame_record_timestamp);
// copy YUV frame data into buffers
memcpy(frame->data[0], y, width * height);
memcpy(frame->data[1], u, (width / 2) * (height / 2));
memcpy(frame->data[2], v, (width / 2) * (height / 2));
// encode the frame
ret = avcodec_send_frame(call->video->h264_encoder_ctx, frame);
if (ret < 0) {
LOGGER_ERROR(av->m->log, "Error sending a frame for encoding:ERROR");
}
ret = avcodec_receive_packet(call->video->h264_encoder_ctx, call->video->h264_out_pic2);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
*i_frame_size = 0;
} else if (ret < 0) {
*i_frame_size = 0;
// fprintf(stderr, "Error during encoding\n");
} else {
// Decoded encoded frame and save him to file
saveInFile(call->video->h264_decoder_ctx, frame, call->video->h264_out_pic2, "/home/user/testSave");
// printf("Write packet %3"PRId64" (size=%5d)\n", call->video->h264_out_pic2->pts, call->video->h264_out_pic2->size);
// fwrite(call->video->h264_out_pic2->data, 1, call->video->h264_out_pic2->size, outfile);
global_encoder_delay_counter++;
if (global_encoder_delay_counter > 60) {
global_encoder_delay_counter = 0;
LOGGER_DEBUG(av->m->log, "enc:delay=%ld",
(long int)(frame->pts - (int64_t)call->video->h264_out_pic2->pts)
);
}
*i_frame_size = call->video->h264_out_pic2->size;
*video_frame_record_timestamp = (uint64_t)call->video->h264_out_pic2->pts;
result = 0;
}
av_frame_free(&frame);
return result;
}
Decode and save frame code:
void saveInFile(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt, const char *filename)
{
if (!pkt)
return;
char buf[1024];
int ret;
static int curNumber = 0;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0 && ret != AVERROR_EOF)
{
fprintf(stderr, "Error sending a packet for decoding'\n");
if ( ret == AVERROR(EAGAIN))
return;
if (ret == AVERROR(EINVAL))
return;
if (ret == AVERROR(ENOMEM))
return;
}
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) )
return;
if (ret == AVERROR_EOF)
{
return;
}
else if (ret < 0)
{
fprintf(stderr, "Error during decoding\n");
}
printf("saving frame %3d\n", dec_ctx->frame_number);
sprintf(buf, "%s%d", filename, curNumber);
curNumber++;
pgm_save(frame->data[0], frame->linesize[0], frame->width, frame->height, buf);
}
void pgm_save(unsigned char* buf, int wrap, int xsize, int ysize, char *filename)
{
FILE *f;
int i;
f = fopen(filename, "w");
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);
}
After this manipulation I have smth like that:

Reading motion vectors of every 60th frame in video file

I have the following code which reads a video files and extracts motion vectors from each frame and outputs them to stdout:
#include <libavutil/motion_vector.h>
#include <libavformat/avformat.h>
static AVFormatContext *fmt_ctx = NULL;
static AVCodecContext *video_dec_ctx = NULL;
static AVStream *video_stream = NULL;
static const char *src_filename = NULL;
static int video_stream_idx = -1;
static AVFrame *frame = NULL;
static int video_frame_count = 0;
static int decode_packet(const AVPacket *pkt)
{
//fprintf(stderr, "%d\n", video_dec_ctx->width);
int ret = avcodec_send_packet(video_dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error while sending a packet to the decoder: %s\n", av_err2str(ret));
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_frame(video_dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error while receiving a frame from the decoder: %s\n", av_err2str(ret));
return ret;
}
if (ret >= 0) {
int i;
AVFrameSideData *sd;
video_frame_count++;
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
if (sd) {
const AVMotionVector *mvs = (const AVMotionVector *)sd->data;
for (i = 0; i < sd->size / sizeof(*mvs); i++) {
const AVMotionVector *mv = &mvs[i];
printf("%d,%4d,%4d,%4d\n",
video_frame_count,
abs(mv->src_x - mv->dst_x),
abs(mv->src_y - mv->dst_y));
}
}
av_frame_unref(frame);
}
}
return 0;
}
static int open_codec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
{
int ret;
AVStream *st;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;
AVDictionary *opts = NULL;
ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0);
if (ret < 0) {
fprintf(stderr, "Could not find %s stream in input file '%s'\n",
av_get_media_type_string(type), src_filename);
return ret;
} else {
int stream_idx = ret;
st = fmt_ctx->streams[stream_idx];
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx) {
fprintf(stderr, "Failed to allocate codec\n");
return AVERROR(EINVAL);
}
ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters to codec context\n");
return ret;
}
/* Init the video decoder */
av_dict_set(&opts, "flags2", "+export_mvs", 0);
if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
fprintf(stderr, "Failed to open %s codec\n",
av_get_media_type_string(type));
return ret;
}
video_stream_idx = stream_idx;
video_stream = fmt_ctx->streams[video_stream_idx];
video_dec_ctx = dec_ctx;
}
return 0;
}
int main(int argc, char **argv)
{
int ret = 0;
AVPacket pkt = { 0 };
if (argc != 2) {
fprintf(stderr, "Usage: %s <video>\n", argv[0]);
exit(1);
}
src_filename = argv[1];
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
fprintf(stderr, "Could not open source file %s\n", src_filename);
exit(1);
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
open_codec_context(fmt_ctx, AVMEDIA_TYPE_VIDEO);
av_dump_format(fmt_ctx, 0, src_filename, 0);
if (!video_stream) {
fprintf(stderr, "Could not find video stream in the input, aborting\n");
ret = 1;
goto end;
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
ret = AVERROR(ENOMEM);
goto end;
}
printf("framenum,dx,dy\n");
/* read frames from the file */
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_idx)
ret = decode_packet(&pkt);
av_packet_unref(&pkt);
if (ret < 0)
break;
}
/* flush cached frames */
decode_packet(NULL);
end:
avcodec_free_context(&video_dec_ctx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
return ret < 0;
}
Instead and outputting every frame, I only want to read one frame every 60 frames. The speed of the program is very important so I want to eliminate as much unnecessary code as possible. The problem is I'm having a hard time understanding how to advance the video stream without reading in new frames. I call av_read_frame(fmt_ctx, &pkt) to get packet info that is decoded by decode_packet and then goes on to read the next, but I can't find a way to only get packet info for one frame out of each 60.
Use av_seek_frame() to read every 60th frame.

How to cut video with FFmpeg C API

How can I cut video with FFmpeg C API? From 00:10:00 to 00:20:00 for example.
What functions I need to use?
I convert video using this function:
int convert(char *file) {
AVFrame *frame;
AVPacket inPacket, outPacket;
if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "convert(): cannot open out file\n");
return 0;
}
avformat_write_header(outFormatContext, NULL);
frame = avcodec_alloc_frame();
av_init_packet(&inPacket);
while(av_read_frame(inFormatContext, &inPacket) >= 0) {
if(inPacket.stream_index == inVideoStreamIndex) {
avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
if(frameFinished) {
av_init_packet(&outPacket);
avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
if(outputed) {
if (av_write_frame(outFormatContext, &outPacket) != 0) {
fprintf(stderr, "convert(): error while writing video frame\n");
return 0;
}
}
av_free_packet(&outPacket);
}
}
}
av_write_trailer(outFormatContext);
av_free_packet(&inPacket);
return 1;
}
As Wagner Patriota says, "if you just wanna cut the video, you don't need to reencode the video if you want". Here is the code based on ffmpeg remuxing.c example that you don't need to reencode the video.
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
tag,
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
pkt->stream_index);
}
int cut_video(double from_seconds, double end_seconds, const char* in_filename, const char* out_filename) {
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
int ret, i;
av_register_all();
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", in_filename);
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
goto end;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", out_filename);
goto end;
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
goto end;
}
// int indexs[8] = {0};
// int64_t start_from = 8*AV_TIME_BASE;
ret = av_seek_frame(ifmt_ctx, -1, from_seconds*AV_TIME_BASE, AVSEEK_FLAG_ANY);
if (ret < 0) {
fprintf(stderr, "Error seek\n");
goto end;
}
int64_t *dts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
memset(dts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
int64_t *pts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
memset(pts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
while (1) {
AVStream *in_stream, *out_stream;
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
log_packet(ifmt_ctx, &pkt, "in");
if (av_q2d(in_stream->time_base) * pkt.pts > end_seconds) {
av_free_packet(&pkt);
break;
}
if (dts_start_from[pkt.stream_index] == 0) {
dts_start_from[pkt.stream_index] = pkt.dts;
printf("dts_start_from: %s\n", av_ts2str(dts_start_from[pkt.stream_index]));
}
if (pts_start_from[pkt.stream_index] == 0) {
pts_start_from[pkt.stream_index] = pkt.pts;
printf("pts_start_from: %s\n", av_ts2str(pts_start_from[pkt.stream_index]));
}
/* copy packet */
pkt.pts = av_rescale_q_rnd(pkt.pts - pts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts - dts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
if (pkt.pts < 0) {
pkt.pts = 0;
}
if (pkt.dts < 0) {
pkt.dts = 0;
}
pkt.duration = (int)av_rescale_q((int64_t)pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
log_packet(ofmt_ctx, &pkt, "out");
printf("\n");
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Error muxing packet\n");
break;
}
av_free_packet(&pkt);
}
free(dts_start_from);
free(pts_start_from);
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
If you just wanna cut the video, you don't need to reencode the video if you want.
So I am supposing you wanna cut and reencode for some reason. So, based on your code:
Observe you must to have access to the video AVStream* structure... I named it as inVideoStream.
int convert_and_cut(char *file, float starttime, float endtime) {
AVFrame *frame;
AVPacket inPacket, outPacket;
if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "convert(): cannot open out file\n");
return 0;
}
// seek to the start time you wish.
// BEGIN
AVRational default_timebase;
default_timebase.num = 1;
default_timebase.den = AV_TIME_BASE;
// suppose you have access to the "inVideoStream" of course
int64_t starttime_int64 = av_rescale_q((int64_t)( starttime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);
int64_t endtime_int64 = av_rescale_q((int64_t)( endtime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);
if(avformat_seek_file(inFormatContext, inVideoStreamIndex, INT64_MIN, starttime_int64, INT64_MAX, 0) < 0) {
// error... do something...
return 0; // usually 0 is used for success in C, but I am following your code.
}
avcodec_flush_buffers( inVideoStream->codec );
// END
avformat_write_header(outFormatContext, NULL);
frame = avcodec_alloc_frame();
av_init_packet(&inPacket);
// you used avformat_seek_file() to seek CLOSE to the point you want... in order to give precision to your seek,
// just go on reading the packets and checking the packets PTS (presentation timestamp)
while(av_read_frame(inFormatContext, &inPacket) >= 0) {
if(inPacket.stream_index == inVideoStreamIndex) {
avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
// this line guarantees you are getting what you really want.
if(frameFinished && frame->pkt_pts >= starttime_int64 && frame->pkt_pts <= endtime_int64) {
av_init_packet(&outPacket);
avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
if(outputed) {
if (av_write_frame(outFormatContext, &outPacket) != 0) {
fprintf(stderr, "convert(): error while writing video frame\n");
return 0;
}
}
av_free_packet(&outPacket);
}
// exit the loop if you got the frames you want.
if(frame->pkt_pts > endtime_int64) {
break;
}
}
}
av_write_trailer(outFormatContext);
av_free_packet(&inPacket);
return 1;
}
In addition, as ustin says, the code based on ffmpeg remuxing.c example.
add out_stream->time_base = in_stream->time_base; before out_stream->codec->codec_tag = 0;
add int64_t *start_from = NULL; after int stream_mapping_size = 0;
add start_from = av_mallocz_array(stream_mapping_size, sizeof(*start_from)); after stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));
add start_from[stream_mapping[i]] = INT16_MIN; after stream_mapping[i] = stream_index++;
add
if (start_from[pkt.stream_index] == INT16_MIN) {
int64_t dts = pkt.dts;
int64_t pts = pkt.pts;
int64_t min_ts = dts > pts ? pts : dts;
start_from[pkt.stream_index] = min_ts < 0 ? 0 : min_ts;
}
After
if (pkt.stream_index >= stream_mapping_size ||
stream_mapping[pkt.stream_index] < 0) {
av_packet_unref(&pkt);
continue;
}
change justin code, about pts/dst set value to this:
pkt.pts = av_rescale_q_rnd(pkt.pts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
add free(start_from); before end:
Tips: start/end timestamp like justin says

Play libav decodec audio through portaudio asynchronously

I am writing a python extension which can play audio using libav and portaudio.
I've got this working code. However, this is a blocking function. I'm trying to implement asynchronous playback using a portaudio callback function, but I get a segment fault of which I have no clue what caused it.
I currently have the following code:
typedef struct {
/* Python */
PyObject_HEAD
PyObject *filepath;
PyObject *duration;
PyObject *sample_rate;
PyObject *channels;
/* av */
AVFormatContext *fmt_ctx;
AVStream *audio_stream;
AVCodecContext *codec_ctx;
AVDictionaryEntry *current_tag; /* Used for iteration: for tag in song */
/* portaudio */
PaStream *pa_stream;
unsigned int frame_count;
unsigned int frame_index;
unsigned int data_index;
AVFrame *frames;
} Song;
...
#define PaPy_CHECK_ERROR(error) \
if (error != paNoError) { \
PyErr_SetString(PyExc_OSError, Pa_GetErrorText(error)); \
return NULL; \
}
static int pa_callback(const void *input_buffer,
void *output_buffer,
unsigned long frames_per_buffer,
const PaStreamCallbackTimeInfo* time_info,
PaStreamCallbackFlags status_flags,
void *user_data)
{
Song *self = (Song *)user_data;
unsigned int i = 0;
int finished = 0;
(void) input_buffer;
(void) time_info;
uint16_t *out = (uint16_t *)output_buffer;
AVFrame frame = self->frames[self->frame_index];
for (; i < frames_per_buffer; i++) {
if (self->data_index++ > frame.nb_samples) {
frame = self->frames[self->frame_index++];
self->data_index = 0;
}
if (self->frame_index >= self->frame_count -1) {
return -1;
}
*out++ = (*frame.data)[self->data_index];
}
return finished;
}
static PyObject *
Song_play(Song *self)
{
AVCodec *codec = avcodec_find_decoder(self->audio_stream->codec->codec_id);
if (codec == NULL) {
return NULL;
}
if (avcodec_find_decoder(self->codec_ctx->codec_id) < 0) {
return NULL;
}
if (avcodec_open2(self->codec_ctx, codec, NULL) < 0) {
return NULL;
}
PaSampleFormat sample_fmt;
switch (self->codec_ctx->sample_fmt) {
case AV_SAMPLE_FMT_U8:
sample_fmt = paUInt8;
printf("uint 8\n");
break;
case AV_SAMPLE_FMT_S16:
sample_fmt = paInt16;
printf("uint 16\n");
break;
case AV_SAMPLE_FMT_S32:
sample_fmt = paInt32;
printf("int 16\n");
break;
case AV_SAMPLE_FMT_FLT:
sample_fmt = paFloat32;
printf("float\n");
break;
default:
PyErr_SetString(PyExc_OSError,
"Unable to parse audio sample format.");
return NULL;
}
PaError err = Pa_OpenDefaultStream(&self->pa_stream,
0,
self->codec_ctx->channels,
sample_fmt,
self->codec_ctx->sample_rate,
paFramesPerBufferUnspecified,
pa_callback,
self);
PaPy_CHECK_ERROR(err)
AVPacket packet;
self->frames = malloc(self->frame_count * sizeof(AVFrame));
unsigned int i = 0;
while (av_read_frame(self->fmt_ctx, &packet) >= 0) {
if (packet.stream_index != self->audio_stream->index) {
continue;
}
AVFrame frame;
int got_frame;
int ret = avcodec_decode_audio4(self->codec_ctx, &frame,
&got_frame, &packet);
if (ret < 0) {
continue;
}
if (ret != packet.size) {
continue;
}
if (got_frame) {
self->frames[i] = frame;
/* This worked, but it is a blocking call. */
/*err = Pa_WriteStream(self->pa_stream, *frame.data,*/
/* frame.nb_samples);*/
/*PaPy_CHECK_ERROR(err)*/
i++;
}
/* av_free_packet(&packet);*/
}
err = Pa_StartStream(self->pa_stream);
PaPy_CHECK_ERROR(err)
av_seek_frame(self->fmt_ctx, self->audio_stream->index, 0, 0);
Py_RETURN_NONE;
}
But this just gives me noise. The full code can be seen here.
Could someone tell me what's wrong with this code?

FFmpeg: Jpeg file to AVFrame

I need to join several jpg files into video using FFmpeg library. But I have a problem with reading this files. Here is a function which reads image file and makes AVFrame:
AVFrame* OpenImage(const char* imageFileName)
{
AVFormatContext *pFormatCtx;
if(av_open_input_file(&pFormatCtx, imageFileName, NULL, 0, NULL)!=0)
{
printf("Can't open image file '%s'\n", imageFileName);
return NULL;
}
dump_format(pFormatCtx, 0, imageFileName, false);
AVCodecContext *pCodecCtx;
pCodecCtx = pFormatCtx->streams[0]->codec;
pCodecCtx->width = W_VIDEO;
pCodecCtx->height = H_VIDEO;
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;
pFrame = avcodec_alloc_frame();
if (!pFrame)
{
printf("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);
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)
{
printf("Frame is decoded, size %d\n", ret);
pFrame->quality = 4;
return pFrame;
}
else
printf("Error [%d] while decoding frame: %s\n", ret, strerror(AVERROR(ret)));
}
}
This causes no error but creates only black frame, no image. What is wrong?
This code is correct (except of problem with color scheme). There was a bug in adding frame to video.
I used your code as the base for debugging, and finally succeeded.And the code is below
Code description
I used c++11 and FFmpeg 4.2
OpenImage is the 'jpeg file to AVFrame' function
OperationFrame_EncodeAndWrite_Inner_SaveJpg is the 'AVFrame to
jpeg file' function
'int width = 1280; int height = 960; enum AVPixelFormat dst_pixfmt = AV_PIX_FMT_YUV420P;' are the image parameters(what you want) of target AVFrame.
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
//#include <libavfilter/avfilter.h">
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libavutil/pixfmt.h>
#include <libavutil/timecode.h>
#include <libavutil/bprint.h>
#include <libavutil/time.h>
#include <libswscale/swscale.h>
}
#include <stdio.h>
#include <string.h>
int OperationFrame_EncodeAndWrite_Inner_SaveJpg(AVFrame *pFrame, const char *out_file) {
int width = pFrame->width;
int height = pFrame->height;
AVFormatContext* pFormatCtx = avformat_alloc_context();
pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);
if( avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
printf("Couldn't open output file.");
return -1;
}
AVStream* pAVStream = avformat_new_stream(pFormatCtx, 0);
if( pAVStream == NULL ) {
return -1;
}
AVCodecContext* pCodecCtx = pAVStream->codec;
pCodecCtx->codec_id = pFormatCtx->oformat->video_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
pCodecCtx->width = width;
pCodecCtx->height = height;
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
// Begin Output some information
av_dump_format(pFormatCtx, 0, out_file, 1);
// End Output some information
AVCodec* pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if( !pCodec ) {
printf("Codec not found.");
return -1;
}
if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 ) {
printf("Could not open codec.");
return -1;
}
//Write Header
avformat_write_header(pFormatCtx, NULL);
int y_size = pCodecCtx->width * pCodecCtx->height;
AVPacket pkt;
av_new_packet(&pkt, y_size * 3);
//
int got_picture = 0;
int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture);
if( ret < 0 ) {
printf("Encode Error.\n");
return -1;
}
if( got_picture == 1 ) {
//pkt.stream_index = pAVStream->index;
ret = av_write_frame(pFormatCtx, &pkt);
}
av_free_packet(&pkt);
//Write Trailer
av_write_trailer(pFormatCtx);
if( pAVStream ) {
avcodec_close(pAVStream->codec);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
return 0;
}
AVFrame* OpenImage(const char* imageFileName)
{
AVFormatContext *pFormatCtx= NULL;
if(avformat_open_input(&(pFormatCtx), imageFileName, NULL, NULL)!=0)
{
printf("Can't open image file '%s'\n", imageFileName);
return NULL;
}
if(avformat_find_stream_info(pFormatCtx, NULL ) < 0){
printf("Can't find stream\n");
return NULL;
}
av_dump_format(pFormatCtx, 0, imageFileName, false);
AVCodecContext *pCodecCtx;
int index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
// pCodecCtx = pFormatCtx->streams[index]->codec;
// pCodecCtx->width = 640;
// pCodecCtx->height = 480;
// pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
AVCodec *dec = avcodec_find_decoder(pFormatCtx->streams[index]->codecpar->codec_id);
pCodecCtx = avcodec_alloc_context3(dec);
avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[index]->codecpar);
// 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_open2(pCodecCtx, pCodec, NULL)<0)
{
printf("Could not open codec\n");
return NULL;
}
//
AVFrame *pFrame;
pFrame = av_frame_alloc();
if (!pFrame)
{
printf("Can't allocate memory for AVFrame\n");
return NULL;
}
int frameFinished;
AVPacket packet;
packet.data = NULL;
packet.size = 0;
int framesNumber = 0;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index != index){
continue;
}
//pFrame = av_frame_alloc();
int ret = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
printf("Frame is decoded, size %d\n", ret);
break;
}
}
AVFrame* dst = av_frame_alloc();
int width = 1280;
int height = 960;
enum AVPixelFormat dst_pixfmt = AV_PIX_FMT_YUV420P;
int numBytes = avpicture_get_size(dst_pixfmt, width, height);
uint8_t *buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill( (AVPicture *)dst, buffer, dst_pixfmt, width, height);
struct SwsContext *convert_ctx=NULL;
enum AVPixelFormat src_pixfmt = (enum AVPixelFormat)pFrame->format;
convert_ctx = sws_getContext(pFrame->width, pFrame->height, pCodecCtx->pix_fmt, width, height, dst_pixfmt,
SWS_POINT, NULL, NULL, NULL);
sws_scale(convert_ctx, pFrame->data, pFrame->linesize, 0, pFrame->height,
dst->data, dst->linesize);
sws_freeContext(convert_ctx);
av_frame_free(&pFrame);
avformat_close_input(&(pFormatCtx));
avcodec_free_context(&pCodecCtx);
dst->format = (int)dst_pixfmt;
dst->width = width;
dst->height = height;
dst->pts = 0;
dst->pkt_pts = 0;
dst->pkt_dts = 0;
return dst;
}
int main(int argc, char *argv[]){
const char* imageFileName = "/data/test/nosignal.png";
const char* outputFile = "/data/test/test.png";
int64_t start_time = av_gettime();
AVFrame* frame = OpenImage(imageFileName);
std::cout<< av_gettime() - start_time <<std::endl;
OperationFrame_EncodeAndWrite_Inner_SaveJpg(frame,outputFile);
}

Resources