I have the following code to transcode video which is closely related to the FFMPEG transcoding example.
However it produced broken video as shown:
It seems like the i-frames are decoded correctly, but the p and b frames are out of order? I thought av_interleaved_write_frame() would rectify that for me. It also seems like the libx264 is not creating any extradata which I thought it would.
Could someone please help me work out why?
Many thanks
#include <stdbool.h>
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>
#define DEBUG(level, format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__)
#define stringify2(var) #var
#define stringify(var) stringify2(var)
#define RASSERT(cond, ...) do { \
if (!(cond)) { \
DEBUG(LOG_FATAL, __FILE__ ":" stringify(__LINE__) " " "Assertion failed! " #cond ". " __VA_ARGS__); \
abort(); \
} \
} while (0)
#define FFCHECK(ret, func) RASSERT(ret == 0, #func " failed: %s (%d)", av_err2str(ret), ret)
typedef struct decode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} decode_context_t;
typedef struct encode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} encode_context_t;
void open_input(decode_context_t *dec, const char *file) {
int ret;
ret = avformat_open_input(&dec->format, file, NULL, NULL);
FFCHECK(ret, "avformat_open_input()");
ret = avformat_find_stream_info(dec->format, NULL);
FFCHECK(ret, "avformat_find_stream_info()");
for (unsigned int i = 0; i < dec->format->nb_streams; ++i) {
AVStream * stream = dec->format->streams[i];
enum AVMediaType type = stream->codecpar->codec_type;
switch (type) {
case AVMEDIA_TYPE_VIDEO:
if (dec->videoStream)
break;
dec->videoStream = stream;
break;
case AVMEDIA_TYPE_AUDIO:
dec->audioStream = stream;
if (dec->audioStream)
break;
break;
default:
break;
}
}
RASSERT(dec->videoStream != NULL, "Didn't find video stream");
const AVCodec * codec = avcodec_find_decoder(dec->videoStream->codecpar->codec_id);
RASSERT(codec, "Failed to find decoder");
dec->videoCodec = avcodec_alloc_context3(codec);
RASSERT(dec->videoCodec, "avcodec_alloc_context3() failed");
ret = avcodec_parameters_to_context(dec->videoCodec, dec->videoStream->codecpar);
FFCHECK(ret, "avcodec_parameters_to_context()");
dec->videoCodec->framerate = av_guess_frame_rate(dec->format, dec->videoStream, NULL);
ret = avcodec_open2(dec->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");
}
void open_output(encode_context_t *enc, const char *file, decode_context_t *dec) {
int ret;
ret = avformat_alloc_output_context2(&enc->format, NULL, NULL, file);
FFCHECK(ret, "avformat_alloc_output_context2()");
enc->videoStream = avformat_new_stream(enc->format, NULL);
RASSERT(enc->videoStream, "avformat_new_stream() failed");
enc->videoStream->id = enc->format->nb_streams - 1;
const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
RASSERT(codec, "Failed to find encoder");
enc->videoCodec = avcodec_alloc_context3(codec);
RASSERT(enc->videoCodec, "avcodec_alloc_context3() failed");
enc->videoCodec->bit_rate = 400000;
enc->videoCodec->width = dec->videoCodec->width;
enc->videoCodec->height = dec->videoCodec->height;
enc->videoCodec->sample_aspect_ratio = dec->videoCodec->sample_aspect_ratio;
enc->videoCodec->time_base = av_inv_q(dec->videoCodec->framerate);
//enc->videoCodec->gop_size = 12;
//enc->videoCodec->max_b_frames = 2;
enc->videoCodec->pix_fmt = dec->videoCodec->pix_fmt;
enc->videoCodec->framerate = dec->videoCodec->framerate;
if (codec->id == AV_CODEC_ID_H264) {
av_opt_set(enc->videoCodec->priv_data, "preset", "slow", 0);
av_opt_set(enc->videoCodec->priv_data, "profile", "high", 0);
av_opt_set(enc->videoCodec->priv_data, "level", "4.1", 0);
}
if (enc->format->flags & AVFMT_GLOBALHEADER)
enc->videoCodec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(enc->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");
ret = avcodec_parameters_from_context(enc->videoStream->codecpar, enc->videoCodec);
FFCHECK(ret, "avcodec_parameters_from_context()");
//enc->videoStream->time_base = enc->videoCodec->time_base;
//enc->videoStream->codecpar->extradata = enc->videoCodec->extradata;
//enc->videoStream->codecpar->extradata_size = enc->videoCodec->extradata_size;
av_dump_format(enc->format, 0, file, 1);
ret = avio_open(&enc->format->pb, file, AVIO_FLAG_WRITE);
FFCHECK(ret, "avio_open()");
ret = avformat_write_header(enc->format, NULL);
FFCHECK(ret, "avformat_write_header()");
}
int main(int argc, const char * argv[]) {
int ret;
if (argc < 3) {
fprintf(stderr, "%s input output\n", argv[0]);
return 1;
}
decode_context_t dec_ctx = {};
decode_context_t *dec = &dec_ctx;
encode_context_t enc_ctx = {};
encode_context_t *enc = &enc_ctx;
open_input(dec, argv[1]);
open_output(enc, argv[2], dec);
while (true) {
AVPacket *packet = av_packet_alloc();
ret = av_read_frame(dec->format, packet);
if (ret < 0)
break;
if (packet->stream_index == dec->videoStream->index) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret == AVERROR(EAGAIN)) {
AVFrame * frame = av_frame_alloc();
while (true) {
ret = avcodec_receive_frame(dec->videoCodec, frame);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_frame()");
ret = avcodec_send_frame(enc->videoCodec, frame);
if (ret == AVERROR(EAGAIN)) {
AVPacket *pkt = av_packet_alloc();
while (true) {
ret = avcodec_receive_packet(enc->videoCodec, pkt);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_packet()");
pkt->stream_index = enc->videoStream->id;
av_packet_rescale_ts(pkt, dec->videoStream->time_base, enc->videoStream->time_base);
ret = av_interleaved_write_frame(enc->format, pkt);
FFCHECK(ret, "av_interleaved_write_frame()");
}
av_packet_free(&pkt);
}
}
av_frame_free(&frame);
} else {
FFCHECK(ret, "avcodec_send_packet()");
}
} else if (packet->stream_index == dec->audioStream->index) {
// Deal with audio
}
av_packet_free(&packet);
}
ret = av_write_trailer(enc->format);
FFCHECK(ret, "av_write_trailer()");
ret = avio_close(enc->format->pb);
FFCHECK(ret, "avio_close()");
// Close some more stuff
return 0;
}
After thinking about this some more, I realised that I wasn't even sure if my decoder was correct. And another thorough inspection of the transcoding example revealed a small difference in behaviour.
Effectively, I was doing this:
while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != AVERROR(EAGAIN)) {
continue;
}
ret = avcodec_receive_frame(dec->videoCodec, frame);
}
Removing the continue and immediately trying to receive frames from the decoder works much better, and fixed my issue.
while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != 0)
abort();
ret = avcodec_receive_frame(dec->videoCodec, frame);
}
I also had the same error in the encoding side so I've fixed it there too.
Related
I am trying to save all frames from a mp4 video in separate JPG files, I have a code that runs and actually saves something to JPG files but files are not recognized as images and nothing is showing.
Below my full code, I am using Visual Studio 2022 in Windows 11 and FFMPEG 5.1. The function that saves the images is save_frame_as_jpeg which is actually an adaption from the code provided here but changing the use of avcodec_encode_video2 for avcodec_send_frame/avcodec_receive_packet as indicated in the documentation.
I am obiously doing something wrong but cannot quite find it, BTW, I know that a simple command (ffmpeg -i input.mp4 -vf fps=1 vid_%d.png) will do this but I am requiring to do it by code.
Any help is appreciated, thanks in advance!
// FfmpegTests.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#pragma warning(disable : 4996)
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavutil/opt.h"
#include "libavutil/avutil.h"
#include "libavutil/error.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/buffersink.h"
#include "libswscale/swscale.h"
}
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swscale.lib")
#include <cstdio>
#include <iostream>
#include <chrono>
#include <thread>
static AVFormatContext* fmt_ctx;
static AVCodecContext* dec_ctx;
AVFilterGraph* filter_graph;
AVFilterContext* buffersrc_ctx;
AVFilterContext* buffersink_ctx;
static int video_stream_index = -1;
const char* filter_descr = "scale=78:24,transpose=cclock";
static int64_t last_pts = AV_NOPTS_VALUE;
static int open_input_file(const char* filename)
{
const AVCodec* dec;
int ret;
if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
return ret;
}
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
return ret;
}
/* select the video stream */
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
return ret;
}
video_stream_index = ret;
/* create decoding context */
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx)
return AVERROR(ENOMEM);
avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar);
/* init the video decoder */
if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
return ret;
}
return 0;
}
static int init_filters(const char* filters_descr)
{
char args[512];
int ret = 0;
const AVFilter* buffersrc = avfilter_get_by_name("buffer");
const AVFilter* buffersink = avfilter_get_by_name("buffersink");
AVFilterInOut* outputs = avfilter_inout_alloc();
AVFilterInOut* inputs = avfilter_inout_alloc();
AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
filter_graph = avfilter_graph_alloc();
if (!outputs || !inputs || !filter_graph) {
ret = AVERROR(ENOMEM);
goto end;
}
/* buffer video source: the decoded frames from the decoder will be inserted here. */
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
time_base.num, time_base.den,
dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
args, NULL, filter_graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
goto end;
}
/* buffer video sink: to terminate the filter chain. */
ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
NULL, NULL, filter_graph);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
goto end;
}
ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
goto end;
}
outputs->name = av_strdup("in");
outputs->filter_ctx = buffersrc_ctx;
outputs->pad_idx = 0;
outputs->next = NULL;
inputs->name = av_strdup("out");
inputs->filter_ctx = buffersink_ctx;
inputs->pad_idx = 0;
inputs->next = NULL;
if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
&inputs, &outputs, NULL)) < 0)
goto end;
if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
goto end;
end:
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
return ret;
}
static void display_frame(const AVFrame* frame, AVRational time_base)
{
int x, y;
uint8_t* p0, * p;
int64_t delay;
if (frame->pts != AV_NOPTS_VALUE) {
if (last_pts != AV_NOPTS_VALUE) {
/* sleep roughly the right amount of time;
* usleep is in microseconds, just like AV_TIME_BASE. */
AVRational timeBaseQ;
timeBaseQ.num = 1;
timeBaseQ.den = AV_TIME_BASE;
delay = av_rescale_q(frame->pts - last_pts, time_base, timeBaseQ);
if (delay > 0 && delay < 1000000)
std::this_thread::sleep_for(std::chrono::microseconds(delay));
}
last_pts = frame->pts;
}
/* Trivial ASCII grayscale display. */
p0 = frame->data[0];
puts("\033c");
for (y = 0; y < frame->height; y++) {
p = p0;
for (x = 0; x < frame->width; x++)
putchar(" .-+#"[*(p++) / 52]);
putchar('\n');
p0 += frame->linesize[0];
}
fflush(stdout);
}
int save_frame_as_jpeg(AVCodecContext* pCodecCtx, AVFrame* pFrame, int FrameNo) {
int ret = 0;
const AVCodec* jpegCodec = avcodec_find_encoder(AV_CODEC_ID_JPEG2000);
if (!jpegCodec) {
return -1;
}
AVCodecContext* jpegContext = avcodec_alloc_context3(jpegCodec);
if (!jpegContext) {
return -1;
}
jpegContext->pix_fmt = pCodecCtx->pix_fmt;
jpegContext->height = pFrame->height;
jpegContext->width = pFrame->width;
jpegContext->time_base = AVRational{ 1,10 };
ret = avcodec_open2(jpegContext, jpegCodec, NULL);
if (ret < 0) {
return ret;
}
FILE* JPEGFile;
char JPEGFName[256];
AVPacket packet;
packet.data = NULL;
packet.size = 0;
av_init_packet(&packet);
int gotFrame;
ret = avcodec_send_frame(jpegContext, pFrame);
if (ret < 0) {
return ret;
}
ret = avcodec_receive_packet(jpegContext, &packet);
if (ret < 0) {
return ret;
}
sprintf(JPEGFName, "c:\\folder\\dvr-%06d.jpg", FrameNo);
JPEGFile = fopen(JPEGFName, "wb");
fwrite(packet.data, 1, packet.size, JPEGFile);
fclose(JPEGFile);
av_packet_unref(&packet);
avcodec_close(jpegContext);
return 0;
}
int main(int argc, char** argv)
{
AVFrame* frame;
AVFrame* filt_frame;
AVPacket* packet;
int ret;
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
frame = av_frame_alloc();
filt_frame = av_frame_alloc();
packet = av_packet_alloc();
if (!frame || !filt_frame || !packet) {
fprintf(stderr, "Could not allocate frame or packet\n");
exit(1);
}
if ((ret = open_input_file(argv[1])) < 0)
goto end;
if ((ret = init_filters(filter_descr)) < 0)
goto end;
while (true)
{
if ((ret = av_read_frame(fmt_ctx, packet)) < 0)
break;
if (packet->stream_index == video_stream_index) {
ret = avcodec_send_packet(dec_ctx, packet);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while sending a packet to the decoder\n");
break;
}
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
else if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while receiving a frame from the decoder\n");
goto end;
}
frame->pts = frame->best_effort_timestamp;
/* push the decoded frame into the filtergraph */
if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
break;
}
/* pull filtered frames from the filtergraph */
while (1) {
ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
if (ret < 0)
goto end;
display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base);
av_frame_unref(filt_frame);
ret = save_frame_as_jpeg(dec_ctx, frame, dec_ctx->frame_number);
if (ret < 0)
goto end;
}
av_frame_unref(frame);
}
}
av_packet_unref(packet);
}
end:
avfilter_graph_free(&filter_graph);
avcodec_free_context(&dec_ctx);
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
av_frame_free(&filt_frame);
av_packet_free(&packet);
if (ret < 0 && ret != AVERROR_EOF) {
char errBuf[AV_ERROR_MAX_STRING_SIZE]{0};
int res = av_strerror(ret, errBuf, AV_ERROR_MAX_STRING_SIZE);
fprintf(stderr, "Error: %s\n", errBuf);
exit(1);
}
exit(0);
}
Well nevermind, I just realized I had an error with the specified codec for JPEG decoding, if somenone's facing this issue you have to use:
*const AVCodec* jpegCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);*
instead of:
*const AVCodec* jpegCodec = avcodec_find_encoder(AV_CODEC_ID_JPEG2000);*
and also add this line:
*jpegContext->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;*
before the call to avcodec_open2
I use libavformat to encapsulate an h264 stream and an aac stream into an mp4 file which is playable. However, when encapsulated into a ts file, it works fine in the Win10 player, but no audio in the vlc player. When encapsulating, the audio stream is printed, but with fprobe, the audio stream is printed with channel=0. What could be the reason for this?
And h264 source file is no pts.So I caculate it by myself.
ffprobe print
ffmpeg print
Here is my code.
#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 num=%d den=%d\n", tag, time_base->num, time_base->den);
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 main()
{
const char* in_filename_v = "test.h264";
const char* in_filename_a = "aoutput.aac";
const char* out_filename = "lol.ts";
//Video Input AVFormatContext
AVFormatContext* ifmt_ctx_v = NULL;
int ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_v %s", in_filename_v);
return -1;
}
//Find Video Stream Info
ret = avformat_find_stream_info(ifmt_ctx_v, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_v stream info");
return -1;
}
//Audio Input AVFormatContext
AVFormatContext* ifmt_ctx_a = NULL;
ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_a %s", in_filename_a);
return -1;
}
//Find Audio Stream Info
ret = avformat_find_stream_info(ifmt_ctx_a, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_a stream info");
return -1;
}
printf("===========Input Information==========\n");
av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);
av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
printf("======================================\n");
//Output AVFormatContext
AVFormatContext* ofmt_ctx = NULL;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{
fprintf(stderr, "cannot alloc OutputFromat context!");
ret = AVERROR_UNKNOWN;
return -1;
}
AVOutputFormat* ofmt = ofmt_ctx->oformat;
//Alloc AVSTREAM
int istream_index_v = 0, istream_index_a = 0, ostream_index_v = 0, ostream_index_a = 0;
for (int i = 0; i < ifmt_ctx_v->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_v->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
continue;
outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}
ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
// Remeber video stream id
istream_index_v = i;
ostream_index_v = 0;
break;
}
for (int i = 0; i < ifmt_ctx_a->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_a->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}
ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
// Remeber audio stream id
istream_index_a = i;
ostream_index_a = 1;
break;
}
printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");
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);
return -1;
}
}
//Write file header
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return -1;
}
//read and write packet
AVPacket* pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "Could not allocate AVPacket\n");
return -1;
}
while (1)
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_v, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_v->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_v)
{
av_packet_unref(pkt);
continue;
}
pkt->stream_index = ostream_index_v;
outstream = ofmt_ctx->streams[pkt->stream_index];
// in log info
log_packet(ifmt_ctx_v, pkt, "in");
if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
//
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}
// duration between two frames(us)
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out");
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
break;
}
}
while (1)
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_a, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_a->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_a)
{
av_packet_unref(pkt);
continue;
}
if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
// duration between two frames(us)
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}
// in log info
log_packet(ifmt_ctx_a, pkt, "in");
pkt->stream_index = ostream_index_a;
outstream = ofmt_ctx->streams[pkt->stream_index];
//change timestamp
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out");
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
break;
}
}
//write file trailer
av_write_trailer(ofmt_ctx);
printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");
}
DVB Insepctor video
DVB Insepctor audio
Thanks for #aergistal.
The Reason is that av_interleaved_write_frame has buffer limit.I
hadn't thought about this before so I write all video packages
firstly and then write all audio packages.In ts files, at front are
lots of video packages, followed by lots of audio packages, and
finally both packages interleaved.
Because of MPEG-TS is a stream consists of packages , so in a long time the player can't find audio packages resulting no voice.
Here is my new code that can work.
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#define EXTRAL 1
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;
FILE* fp = fopen("fflog.log", "a+");
char buf[200];
sprintf(buf, "%s num=%d den=%d\n", tag, time_base->num, time_base->den);
for (int i = 0; *(buf + i) != '\0'; i++)
{
fwrite(buf + i, 1, 1, fp);
}
sprintf(buf, "%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);
for (int i = 0; *(buf + i) != '\0'; i++)
{
fwrite(buf + i, 1, 1, fp);
}
fclose(fp);
}
int main()
{
const char* in_filename_v = "test.h264";
const char* in_filename_a = "aoutput.aac";
const char* out_filename = "lol.ts";
AVFormatContext* ifmt_ctx_v = NULL;
int ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_v %s", in_filename_v);
return -1;
}
ret = avformat_find_stream_info(ifmt_ctx_v, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_v stream info");
return -1;
}
AVFormatContext* ifmt_ctx_a = NULL;
ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_a %s", in_filename_a);
return -1;
}
ret = avformat_find_stream_info(ifmt_ctx_a, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_a stream info");
return -1;
}
#if EXTRAL
printf("===========Input Information==========\n");
av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);
av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
printf("======================================\n");
#endif
AVFormatContext* ofmt_ctx = NULL;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{
fprintf(stderr, "cannot alloc OutputFromat context!");
ret = AVERROR_UNKNOWN;
return -1;
}
AVOutputFormat* ofmt = ofmt_ctx->oformat;
int istream_index_v = 0, istream_index_a = 0, ostream_index_v = 0, ostream_index_a = 0;
for (int i = 0; i < ifmt_ctx_v->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_v->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
continue;
outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}
ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
istream_index_v = i;
ostream_index_v = 0;
break;
}
for (int i = 0; i < ifmt_ctx_a->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_a->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}
ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
istream_index_a = i;
ostream_index_a = 1;
break;
}
#if EXTRAL
printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");
#endif
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);
return -1;
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return -1;
}
AVPacket* pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "Could not allocate AVPacket\n");
return -1;
}
int64_t pts_v = 0, pts_a = 0;
while (1)
{
if (av_compare_ts(pts_a, ifmt_ctx_a->streams[istream_index_a]->time_base, pts_v, ifmt_ctx_v->streams[istream_index_v]->time_base) <= 0)
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_a, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_a->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_a)
{
av_packet_unref(pkt);
continue;
}
if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}
pts_a = pkt->pts;
// in log info
log_packet(ifmt_ctx_a, pkt, "in audio");
pkt->stream_index = ostream_index_a;
outstream = ofmt_ctx->streams[pkt->stream_index];
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out audio");
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
return -1;
}
}
else
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_v, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_v->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_v)
{
av_packet_unref(pkt);
continue;
}
pkt->stream_index = ostream_index_v;
outstream = ofmt_ctx->streams[pkt->stream_index];
if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}
pts_v = pkt->pts;
// in log info
log_packet(ifmt_ctx_v, pkt, "in video");
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out video");
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
return -1;
}
}
}
ret = av_write_trailer(ofmt_ctx);
if (ret < 0)
{
fprintf(stderr, "Error av_write_trailer\n");
}
#if EXTRAL
printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");
#endif
av_packet_free(&pkt);
avformat_close_input(&ifmt_ctx_v);
avformat_close_input(&ifmt_ctx_a);
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
return 0;
}
I just came into contact with the ffmpeg function, and I encountered a problem, av_interleaved_write_frame function fails and returns broken pipe. I don't know what the problem is? Someone on the Internet said there was a disconnect in the client or server,but what causes the disconnection? Please help me, thank you
#include "/usr/local/include/libavcodec/avcodec.h"
#include "/usr/local/include/libavformat/avformat.h"
#include "/usr/local/include/libavfilter/avfilter.h"
#include "/usr/local/include/libavutil/mathematics.h"
#include "/usr/local/include/libavutil/time.h"
extern VideoDataStruct *VideoDataListHeader;
extern PushVideoStruct PushVideoInfo;
extern enum IsPushingVideo IsPushingVideoFlag;
extern UCHAR ChangeAnotherVideo;
typedef long long int64;
#define READ_BUF_LEN 1024*12
extern enum IsStopPushVideo StopPushVideoFlag;
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
int64 dataLen = 0;
while (dataLen < buf_size)
{
if ((VideoDataListHeader != NULL) && (VideoDataListHeader->flag == 1))
{
memcpy(&buf[dataLen], VideoDataListHeader->buf, sizeof(VideoDataListHeader->buf));
dataLen += sizeof(VideoDataListHeader->buf);
VideoDataListHeader->flag = 0;
VideoDataListHeader = VideoDataListHeader->next;
}
else
{
usleep(10000);
}
}
return buf_size;
}
void *PushVideoFunction(void *arg)
{
AVFormatContext *m_pFmtCtx = NULL;
AVPacket pkt;
AVIOContext *m_pIOCtx = NULL;
AVInputFormat *in_fmt = NULL;
int ret = 0;
unsigned int i = 0;
int vid_idx =-1;
unsigned char *m_pIOBuf = NULL;
int m_pIOBuf_size = READ_BUF_LEN;
int64 start_time = 0;
int frame_index = 0;
//const char *rtmp_url = "rtmp://192.168.1.108/mytv/01";
char rtmp_url[140] = {0};
memset(rtmp_url, 0, sizeof(rtmp_url));
strcpy(rtmp_url, PushVideoInfo.VideoServer);
CHAR fileName[64] = {0};
avformat_network_init();
if (strcmp(PushVideoInfo.VideoType, REAL_VIDEO) == 0)
{
m_pIOBuf = (unsigned char*)av_malloc(m_pIOBuf_size);
if(m_pIOBuf == NULL)
{
printf("av malloc failed!\n");
goto end;
}
m_pIOCtx = avio_alloc_context(m_pIOBuf, m_pIOBuf_size, 0, NULL, read_packet, NULL, NULL);
if (!m_pIOCtx)
{
printf("avio alloc context failed!\n");
goto end;
}
m_pFmtCtx = avformat_alloc_context();
if (!m_pFmtCtx)
{
printf("avformat alloc context failed!\n");
goto end;
}
//m_pFmtCtx->probesize = BYTES_PER_FRAME * 8;
m_pFmtCtx->pb = m_pIOCtx;
ret = avformat_open_input(&m_pFmtCtx, "", in_fmt, NULL);
}
else if (strcmp(PushVideoInfo.VideoType, HISTORY_VIDEO) == 0)
{
sprintf(fileName, "%s", VIDEO_FILE_FOLDER);
sprintf(fileName+strlen(fileName), "%s", PushVideoInfo.VideoFile);
ret = avformat_open_input(&m_pFmtCtx, fileName, NULL, NULL);
}
if (ret < 0)
{
printf("avformat open failed!\n");
goto end;
}
ret = avformat_find_stream_info(m_pFmtCtx, 0);
if (ret < 0)
{
printf("could not find stream info!\n");
goto end;
}
for(i = 0; i < m_pFmtCtx->nb_streams; i++)
{
if((m_pFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (vid_idx < 0))
{
vid_idx = i;
}
}
AVFormatContext *octx = NULL;
ret = avformat_alloc_output_context2(&octx, 0, "flv", rtmp_url);
if (ret < 0)
{
printf("avformat alloc output context2 failed!\n");
goto end;
}
av_init_packet(&pkt);
for (i = 0;i < m_pFmtCtx->nb_streams; i++)
{
AVCodec *codec = avcodec_find_decoder(m_pFmtCtx->streams[i]->codecpar->codec_id);
AVStream *out = avformat_new_stream(octx, codec);
ret = avcodec_parameters_copy(out->codecpar, m_pFmtCtx->streams[i]->codecpar);
out->codecpar->codec_tag = 0;
}
ret = avio_open(&octx->pb, rtmp_url, AVIO_FLAG_WRITE);
if (!octx->pb)
{
printf("avio open failed!\n");
goto end;
}
ret = avformat_write_header(octx, 0);
if (ret < 0)
{
printf("avformat write header failed!\n");
goto end;
}
start_time = av_gettime();
AVStream *in_stream, *out_stream;
AVRational time_base1;
AVRational time_base;
AVRational time_base_q;
int64 calc_duration;
int64 pts_time;
int64 now_time;
ChangeAnotherVideo = 0;
while((!StopPushVideoFlag) && (ChangeAnotherVideo == 0))
{
ret = av_read_frame(m_pFmtCtx, &pkt);
if (ret < 0)
{
break;
}
if (pkt.pts == AV_NOPTS_VALUE)
{
time_base1 = m_pFmtCtx->streams[vid_idx]->time_base;
calc_duration = (double)AV_TIME_BASE/av_q2d(m_pFmtCtx->streams[vid_idx]->r_frame_rate);
pkt.pts = (double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
pkt.dts = pkt.pts;
pkt.duration = (double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
}
if (pkt.stream_index == vid_idx)
{
time_base = m_pFmtCtx->streams[vid_idx]->time_base;
time_base_q = (AVRational){1, AV_TIME_BASE};
pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
now_time = av_gettime() - start_time;
if (pts_time > now_time)
{
av_usleep(pts_time - now_time);
}
}
in_stream = m_pFmtCtx->streams[pkt.stream_index];
out_stream = octx->streams[pkt.stream_index];
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
if(pkt.stream_index == vid_idx)
{
printf("Send %8d video frames to output URL\n",frame_index);
frame_index++;
}
ret = av_interleaved_write_frame(octx, &pkt);
if (ret < 0)
{
goto end;
}
av_packet_unref(&pkt);
}
end:
printf("---------------------------------stop push video -------------------------------------------\n");
StopPushVideoFlag = NO_STOP_PUSH;
IsPushingVideoFlag = NO_PUSHING;
ChangeAnotherVideo = 0;
avformat_close_input(&m_pFmtCtx);
if (octx)
{
avio_closep(&octx->pb);
avformat_free_context(octx);
}
/* note: the internal buffer could have changed, and be != avio_ctx_buffer */
if (m_pIOCtx)
{
av_freep(&m_pIOCtx->buffer);
av_freep(&m_pIOCtx);
}
if (ret < 0)
{
printf("Error occured : %s\n", av_err2str(ret));
//return 1;
}
pthread_exit((void*)"push video end!");
}
void PushVideo(void)
{
int ret = 0;
pthread_t pushVideoThread;
ret = pthread_create(&pushVideoThread, NULL, PushVideoFunction, NULL);
if(ret != 0)
{
printf("error : push video thread create failed!\n");
exit(-1);
}
else
{
printf("(debug) push video thread create success!\n");
}
}
This problem has been solved, because the server does not receive NALU of type 0x0a, so the server sends FIN package to disconnect.
I am trying to encoding incoming raw PCM audio data into an AAC encoded audio file. The following crashes with SIGABRT when it hits the avcodec_encode_audio2 call:
aac_encoding.c
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
typedef struct AACEncoder {
AVFormatContext* pFormatCtx;
AVStream* audio_st;
AVCodecContext* pCodecCtx;
AVFrame* pFrame;
AVPacket* pkt;
uint8_t* frame_buf;
} AACEncoder;
AACEncoder *openEncoder(char* out_file) {
AACEncoder* encoder = (AACEncoder*)malloc(sizeof(AACEncoder*));
av_register_all();
AVFormatContext* pFormatCtx = avformat_alloc_context();
encoder->pFormatCtx = pFormatCtx;
AVOutputFormat* outFormat = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = outFormat;
if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
printf("Failed to open output file!\n");
return NULL;
}
AVStream* audio_st = avformat_new_stream(pFormatCtx, 0);
if (audio_st==NULL){
return NULL;
}
encoder->audio_st;
AVCodecContext* pCodecCtx = audio_st->codec;
encoder->pCodecCtx = pCodecCtx;
pCodecCtx->codec_id = outFormat->audio_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP;
pCodecCtx->sample_rate= 48000;
pCodecCtx->channel_layout = AV_CH_LAYOUT_MONO;
pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout);
pCodecCtx->bit_rate = 64000;
av_dump_format(pFormatCtx, 0, out_file, 1);
AVCodec* pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec){
printf("Can not find encoder!\n");
return NULL;
}
if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0){
printf("Failed to open encoder!\n");
return NULL;
}
AVFrame* pFrame = av_frame_alloc();
encoder->pFrame = pFrame;
pFrame->nb_samples= pCodecCtx->frame_size;
pFrame->format= pCodecCtx->sample_fmt;
int size = av_samples_get_buffer_size(NULL, pCodecCtx->channels,pCodecCtx->frame_size,pCodecCtx->sample_fmt, 1);
uint8_t* frame_buf = (uint8_t *)av_malloc(size);
encoder->frame_buf = frame_buf;
avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt,(const uint8_t*)frame_buf, size, 1);
//Write Header
avformat_write_header(pFormatCtx,NULL);
AVPacket pkt;
encoder->pkt = &pkt;
av_new_packet(&pkt,size);
return encoder;
}
int writePCM(AACEncoder* encoder, int16_t* pcmData, size_t pcmSize) {
SwrContext* swr = swr_alloc();
av_opt_set_int(swr, "in_channel_layout", encoder->pCodecCtx->channel_layout, 0);
av_opt_set_int(swr, "out_channel_layout", encoder->pCodecCtx->channel_layout, 0);
av_opt_set_int(swr, "in_sample_rate", encoder->pCodecCtx->sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", encoder->pCodecCtx->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
swr_init(swr);
printf("Initialized SwrContext\n");
fflush(stdout);
int ret = swr_convert(swr, encoder->pFrame->extended_data, pcmSize, &pcmData, pcmSize);
int got_frame=0;
if(ret < 0){
printf("Failed to resample!\n");
return -1;
}
//Encode
ret = avcodec_encode_audio2(encoder->pCodecCtx, encoder->pkt, encoder->pFrame, &got_frame);
printf("Encoded audio using AAC\n");
fflush(stdout);
swr_free(&swr);
if(ret < 0){
printf("Failed to encode!\n");
return -1;
}
if (got_frame==1){
printf("Succeed to encode 1 frame! \tsize:%5d\n", encoder->pkt->size);
encoder->pkt->stream_index = encoder->audio_st->index;
ret = av_write_frame(encoder->pFormatCtx, encoder->pkt);
av_free_packet(encoder->pkt);
}
}
I wanna convert an MPEGTS file into an FLV file with libavcodec APIs(just transformat, video/audio codecs are not changed). Following is the code I found on web. After some hack, it can generate an FLV file, which could not be played. Any clue to fix this?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/rational.h>
#include <libavdevice/avdevice.h>
#include <libavutil/mathematics.h>
#include <libswscale/swscale.h>
static AVStream* add_output_stream(AVFormatContext* output_format_context, AVStream* input_stream) {
AVCodecContext* input_codec_context = NULL;
AVCodecContext* output_codec_context = NULL;
AVStream* output_stream = NULL;
output_stream = avformat_new_stream(output_format_context, 0);
if (!output_stream) {
printf("Call av_new_stream function failed\n");
return NULL;
}
input_codec_context = input_stream->codec;
output_codec_context = output_stream->codec;
output_codec_context->codec_id = input_codec_context->codec_id;
output_codec_context->codec_type = input_codec_context->codec_type;
// output_codec_context->codec_tag = input_codec_context->codec_tag;
output_codec_context->codec_tag = av_codec_get_tag(output_format_context->oformat->codec_tag, input_codec_context->codec_id);
output_codec_context->bit_rate = input_codec_context->bit_rate;
output_codec_context->extradata = input_codec_context->extradata;
output_codec_context->extradata_size = input_codec_context->extradata_size;
if (av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(input_stream->time_base) && av_q2d(input_stream->time_base) < 1.0 / 1000) {
output_codec_context->time_base = input_codec_context->time_base;
output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
} else {
output_codec_context->time_base = input_stream->time_base;
}
switch (input_codec_context->codec_type) {
case AVMEDIA_TYPE_AUDIO:
output_codec_context->channel_layout = input_codec_context->channel_layout;
output_codec_context->sample_rate = input_codec_context->sample_rate;
output_codec_context->channels = input_codec_context->channels;
output_codec_context->frame_size = input_codec_context->frame_size;
if ((input_codec_context->block_align == 1 && input_codec_context->codec_id == CODEC_ID_MP3) || input_codec_context->codec_id == CODEC_ID_AC3) {
output_codec_context->block_align = 0;
} else {
output_codec_context->block_align = input_codec_context->block_align;
}
break;
case AVMEDIA_TYPE_VIDEO:
output_codec_context->pix_fmt = input_codec_context->pix_fmt;
output_codec_context->width = input_codec_context->width;
output_codec_context->height = input_codec_context->height;
output_codec_context->has_b_frames = input_codec_context->has_b_frames;
if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// output_codec_context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
break;
default:
break;
}
return output_stream;
}
int main(int argc, char* argv[]) {
const char* input = argv[1];
const char* output_prefix = NULL;
char* segment_duration_check = 0;
const char* index = NULL;
char* tmp_index = NULL;
const char* http_prefix = NULL;
long max_tsfiles = 0;
double prev_segment_time = 0;
double segment_duration = 0;
AVInputFormat* ifmt = NULL;
AVOutputFormat* ofmt = NULL;
AVFormatContext* ic = NULL;
AVFormatContext* oc = NULL;
AVStream* video_st = NULL;
AVStream* audio_st = NULL;
AVCodec* codec = NULL;
AVDictionary* pAVDictionary = NULL;
av_register_all();
av_log_set_level(AV_LOG_DEBUG);
char szError[256] = {0};
int nRet = avformat_open_input(&ic, input, ifmt, &pAVDictionary);
if (nRet != 0) {
av_strerror(nRet, szError, 256);
printf(szError);
printf("\n");
printf("Call avformat_open_input function failed!\n");
return 0;
}
if (avformat_find_stream_info(ic, NULL) < 0) {
printf("Call av_find_stream_info function failed!\n");
return 0;
}
ofmt = av_guess_format(NULL, argv[2], NULL);
if (!ofmt) {
printf("Call av_guess_format function failed!\n");
return 0;
}
oc = avformat_alloc_context();
if (!oc) {
printf("Call av_guess_format function failed!\n");
return 0;
}
oc->oformat = ofmt;
int video_index = -1, audio_index = -1;
unsigned int i;
for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
switch (ic->streams[i]->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
video_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
video_st = add_output_stream(oc, ic->streams[i]);
if (video_st->codec->codec_id == CODEC_ID_H264) {
video_st->codec->opaque = av_bitstream_filter_init("h264_mp4toannexb");
}
break;
case AVMEDIA_TYPE_AUDIO:
audio_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
audio_st = add_output_stream(oc, ic->streams[i]);
if (audio_st->codec->codec_id == CODEC_ID_AAC && !audio_st->codec->extradata_size) {
audio_st->codec->opaque = av_bitstream_filter_init("aac_adtstoasc");
}
break;
default:
ic->streams[i]->discard = AVDISCARD_ALL;
break;
}
}
codec = avcodec_find_decoder(video_st->codec->codec_id);
if (codec == NULL) {
printf("Call avcodec_find_decoder function failed!\n");
return 0;
}
if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
printf("Call avcodec_open function failed !\n");
return 0;
}
if (avio_open(&oc->pb, argv[2], AVIO_FLAG_WRITE) < 0) {
return 0;
}
if (avformat_write_header(oc, &pAVDictionary)) {
printf("Call avformat_write_header function failed.\n");
return 0;
}
int decode_done = 0;
do {
AVPacket packet;
decode_done = av_read_frame(ic, &packet);
if (decode_done < 0) {
break;
}
if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY) && video_st->codec->opaque != NULL) {
AVPacket pkt = packet;
int a = av_bitstream_filter_filter(video_st->codec->opaque, video_st->codec, NULL, &pkt.data, &pkt.size,
packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
if (a == 0) {
memmove(packet.data, pkt.data, pkt.size);
packet.size = pkt.size;
} else if (a > 0) {
packet = pkt;
}
}
else if (packet.stream_index == audio_index && audio_st->codec->opaque != NULL) {
AVPacket pkt = packet;
int a = av_bitstream_filter_filter(audio_st->codec->opaque, audio_st->codec, NULL, &pkt.data, &pkt.size,
packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
if (a == 0) {
memmove(packet.data, pkt.data, pkt.size);
packet.size = pkt.size;
} else if (a > 0) {
packet = pkt;
}
}
nRet = av_interleaved_write_frame(oc, &packet);
if (nRet < 0) {
printf("Call av_interleaved_write_frame function failed\n");
} else if (nRet > 0) {
printf("End of stream requested\n");
av_free_packet(&packet);
break;
}
av_free_packet(&packet);
} while(!decode_done);
av_write_trailer(oc);
av_bitstream_filter_close(video_st->codec->opaque);
av_bitstream_filter_close(audio_st->codec->opaque);
avcodec_close(video_st->codec);
unsigned int k;
for(k = 0; k < oc->nb_streams; k++) {
av_freep(&oc->streams[k]->codec);
av_freep(&oc->streams[k]);
}
av_free(oc);
getchar();
return 0;
}