[Libav-user] [segmentation fault]video encode question

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[Libav-user] [segmentation fault]video encode question

huyanpingz

Dear all,

I am trying to decode an flv file to Frame and encode them after some modifies, then I will send it to a rtmp server. but I got segmentation fault when I called the `av_write_frame`. I have searched in google and other website, but it doesn’t help.


compile command: gcc src/encode.c -o encode.out -g -v -I /usr/local/ffmpeg/include -L /usr/local/ffmpeg/lib -lavformat -lavcodec -lavutil

run command: encode.out /tmp/out.flv rtmp://domain/live/livestream

code is here:

#include <math.h>

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#include <libswscale/swscale.h>
#include <libavutil/log.h>
#include <libavutil/mathematics.h>
#include <stdio.h>


#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

#define STREAM_DURATION 20
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */ //AV_PIX_FMT_NV12;
#define VIDEO_CODEC_ID CODEC_ID_H264

/* video output */
static AVFrame *frame;

static AVPicture src_picture, dst_picture;

AVCodec *encoder;
AVCodecContext *outputCodecCtx = NULL;
AVFormatContext *outputFormatCtx;

AVFormatContext *inputFormatCtx = NULL;
AVCodecContext *inputCodecCtx = NULL;
int video_index = -1;


static int open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
int ret;
AVCodecContext *c = st->codec;

/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open video codec.\n", avcodec_get_name(c->codec_id));
}
else {

/* allocate and init a re-usable frame */
frame = av_frame_alloc();
if (!frame) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate video frame.\n");
ret = -1;
}
else {
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;

/* Allocate the encoded raw picture. */
ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate picture.\n");
}
else {
/* copy data and linesize picture pointers to frame */
*((AVPicture *)frame) = dst_picture;
}
}
}

return ret;
}


static void fill_yuv_image(AVPicture *pict, int frame_index, int width, int height)
{
int x, y, i;

i = frame_index;

/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;

/* Cb and Cr */
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
}
}
}

static int write_video_frame(AVFormatContext *oc, AVStream *st, int frameCount, AVFrame *frame, int64_t start_time)
{
int ret = 0;
AVCodecContext *c = st->codec;
printf("start_time %d\n", start_time);

fill_yuv_image(&dst_picture, frameCount, c->width, c->height);

AVPacket pkt = { 0 };
int got_packet;
av_init_packet(&pkt);

/* encode the image */
frame->pts = frameCount;
ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error encoding video frame.\n");
}
else {
if (got_packet) {
pkt.stream_index = st->index;
pkt.pts = av_rescale_q_rnd(pkt.pts, inputFormatCtx->streams[video_index]->time_base,
outputFormatCtx->streams[st->index]->time_base, AV_ROUND_NEAR_INF);
ret = av_write_frame(oc, &pkt);

AVRational time_base = inputFormatCtx->streams[video_index]->time_base;
AVRational time_base_q = {1, AV_TIME_BASE};
int64_t pts_time = av_rescale_q(pkt.pts, time_base, time_base_q);
int64_t now_time = av_gettime() - start_time;
int64_t sleep_time = pts_time - now_time;
printf("pts time %d, now_time %d, start_time %d\n", pts_time, now_time, start_time);
if (pts_time > now_time){
printf("sleep %d\n", sleep_time);
av_usleep(pts_time - now_time);
}

if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error while writing video frame.\n");
}
}
}

return ret;
}

int open_output_file(const char* filename) {
avformat_alloc_output_context2(&outputFormatCtx, NULL, "flv", filename);

if (!outputFormatCtx) {
av_log(NULL, AV_LOG_FATAL, "Could not allocate an output context for '%s'.\n", filename);
return -1;
}

if (!outputFormatCtx->oformat) {
av_log(NULL, AV_LOG_FATAL, "Could not create the output format for '%s'.\n", filename);
return -1;
}
}

static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
{
AVCodecContext *c, *input_c;
AVStream *st, *input_stream;

input_stream = inputFormatCtx->streams[video_index];
input_c = input_stream->codec;

/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
av_log(NULL, AV_LOG_ERROR, "Could not find encoder for '%s'.\n", avcodec_get_name(codec_id));
}
else {
st = avformat_new_stream(oc, *codec);
if (!st) {
av_log(NULL, AV_LOG_ERROR, "Could not allocate stream.\n");
}
else {
st->id = oc->nb_streams - 1;
st->time_base.den = st->pts.den = input_stream->time_base.den;
st->time_base.num = st->pts.num = input_stream->time_base.num;

c = st->codec;
c->codec_id = codec_id;
c->bit_rate = input_c->bit_rate;
c->width = input_c->width;
c->height = input_c->height;
c->time_base.den = input_c->time_base.den;
c->time_base.num = input_c->time_base.num;
c->gop_size = input_c->gop_size; /* emit one intra frame every twelve frames at most */
c->pix_fmt = input_c->pix_fmt;
}
}

return st;
}

int open_output_file2(const char *filename) {
AVStream *out_stream;
AVStream *in_stream;
AVCodecContext *dec_ctx, *enc_ctx;
AVCodec *encoder;
int ret;
unsigned int i;

outputFormatCtx = NULL;
avformat_alloc_output_context2(&outputFormatCtx, NULL, "flv", filename);
if (!outputFormatCtx) {
av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
return AVERROR_UNKNOWN;
}


for (i = 0; i < inputFormatCtx->nb_streams; i++) {
out_stream = avformat_new_stream(outputFormatCtx, NULL);
if (!out_stream) {
av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
return AVERROR_UNKNOWN;
}

in_stream = inputFormatCtx->streams[i];
dec_ctx = in_stream->codec;
enc_ctx = out_stream->codec;

if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
|| dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
/* in this example, we choose transcoding to same codec */
encoder = avcodec_find_encoder(dec_ctx->codec_id);
if (!encoder) {
av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
return AVERROR_INVALIDDATA;
}

/* In this example, we transcode to same properties (picture size,
* sample rate etc.). These properties can be changed for output
* streams easily using filters */
if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
enc_ctx->height = dec_ctx->height;
enc_ctx->width = dec_ctx->width;
enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
/* take first format from list of supported formats */
if (encoder->pix_fmts)
enc_ctx->pix_fmt = encoder->pix_fmts[0];
else
enc_ctx->pix_fmt = dec_ctx->pix_fmt;
/* video time_base can be set to whatever is handy and supported by encoder */
enc_ctx->time_base = dec_ctx->time_base;
} else {
enc_ctx->sample_rate = dec_ctx->sample_rate;
enc_ctx->channel_layout = dec_ctx->channel_layout;
enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
/* take first format from list of supported formats */
enc_ctx->sample_fmt = encoder->sample_fmts[0];
enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
}

/* Third parameter can be used to pass settings to encoder */
ret = avcodec_open2(enc_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
return ret;
}
} else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
return AVERROR_INVALIDDATA;
} else {
/* if this stream must be remuxed */
ret = avcodec_copy_context(outputFormatCtx->streams[i]->codec,
inputFormatCtx->streams[i]->codec);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\n");
return ret;
}
}

if (outputFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

}
av_dump_format(outputFormatCtx, 0, filename, 1);

if (!(outputFormatCtx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&outputFormatCtx->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
return ret;
}
}

/* init muxer, write output file header */
ret = avformat_write_header(outputFormatCtx, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
return ret;
}

return 0;
}

int encode(AVFrame *pFrame, AVPacket *packet) {
AVCodecContext * context = outputFormatCtx->streams[0]->codec;
int got_packet, ret;
av_init_packet(packet);
ret = avcodec_encode_video2(context, packet, pFrame, &got_packet);

if(ret < 0) {
av_log(context, AV_LOG_ERROR, "encode failed\n");
return -1;
}

if(got_packet) {
return 0;
}

return 1;
}

static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
{
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
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);
}

static int open_input_file(char *filename)
{
AVCodecContext *inputCodecCtxOrig = NULL;
AVCodec *pCodec = NULL;
int ret, i;

if((ret = avformat_open_input(&inputFormatCtx, filename, NULL, NULL)) != 0) {
av_log(inputFormatCtx, AV_LOG_ERROR, "could not open input file\n");
return ret;
}

if((ret = avformat_find_stream_info(inputFormatCtx, NULL)) < 0) {
av_log(inputFormatCtx, AV_LOG_ERROR, "could not find stream info");
return ret;
}

// Dump information about file onto standard error
av_dump_format(inputFormatCtx, 0, filename, 0);

// Find the first video stream
for (i = 0; i < inputFormatCtx->nb_streams; i++)
if (inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
video_index = i;
break;
}
if (video_index == -1)
return -1; // Didn't find a video stream


// Get a pointer to the codec context for the video stream
inputCodecCtxOrig = inputFormatCtx->streams[video_index]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(inputCodecCtxOrig->codec_id);
if (pCodec == NULL) {
av_log(inputFormatCtx, AV_LOG_ERROR, "Unsupported codec!\n");
return -1; // Codec not found
}
// Copy context
inputCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(inputCodecCtx, inputCodecCtxOrig) != 0) {
av_log(inputCodecCtx, AV_LOG_ERROR, "Couldn't copy codec context");
return -1; // Error copying codec context
}

// Open codec
if (avcodec_open2(inputCodecCtx, pCodec, NULL) < 0)
return -1; // Could not open codec

return 0;
}

static int decode(AVFrame *pFrame)
{
AVPacket packet;
int ret, frameFinished;
while (av_read_frame(inputFormatCtx, &packet) >= 0) {
log_packet(inputFormatCtx, &packet);
// Is this a packet from the video stream?
if (packet.stream_index == video_index) {
// Decode video frame
ret = avcodec_decode_video2(inputCodecCtx, pFrame, &frameFinished, &packet);
if(ret < 0) {
av_log(inputCodecCtx, AV_LOG_ERROR, "could not decode package\n");
return -1;
}
// Did we get a video frame?
if (frameFinished) {
return 0;
}
}

// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}

return -1;
}


int main(int argc, char* argv[]) {
av_register_all();
avformat_network_init();
av_log_set_level(AV_LOG_DEBUG);
AVStream *video_st;
AVFrame *pFrame;
AVCodec *video_codec;
int ret;

open_input_file(argv[1]);
open_output_file(argv[2]);
video_st = add_stream(outputFormatCtx, &video_codec, AV_CODEC_ID_H264);

/* Now that all the parameters are set, we can open the video codec and allocate the necessary encode buffers. */
if (video_st) {
av_log(NULL, AV_LOG_DEBUG, "Video stream codec %s.\n ", avcodec_get_name(video_st->codec->codec_id));

ret = open_video(outputFormatCtx, video_codec, video_st);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Open video stream failed.\n");
return -1;
}
}
else {
av_log(NULL, AV_LOG_FATAL, "Add video stream for the codec '%s' failed.\n", avcodec_get_name(AV_CODEC_ID_H264));
return -1;
}

av_dump_format(outputFormatCtx, 0, argv[2], 1);
ret = avformat_write_header(outputFormatCtx, NULL);
if (ret != 0) {
av_log(NULL, AV_LOG_ERROR, "Failed to connect to RTSP server for '%s'.\n", argv[2]);
return -1;
}

AVFormatContext *out = outputFormatCtx;

// Allocate video frame
pFrame = av_frame_alloc();


int frameCount = 0;
int64_t start_time = av_gettime();
printf("start_time %d \n", start_time);
while(decode(pFrame) == 0) {
frameCount++;
// do something with frame
AVPacket packet = {0};
write_video_frame(outputFormatCtx, video_st, frameCount, pFrame, start_time);

// ret = encode(pFrame, &packet);
// printf("ret:%d\n", ret);
// if(ret != 0) continue;
// ret = av_write_frame(out, &packet);
//
// printf("out format:\n");
//log_packet(outputFormatCtx, &packet);
// if(ret < 0) {
// av_log(outputFormatCtx, AV_LOG_ERROR, "write frame failed\n");
// }
// ret = flush_encoder(outputFormatCtx, 0);
// if (ret < 0) {
// printf("Flushing encoder failed\n");
// return -1;
// }
}
}

_______________________________________________
Libav-user mailing list
[hidden email]
http://ffmpeg.org/mailman/listinfo/libav-user
Loading...