Closed wzl281158150 closed 3 years ago
hi there, I don't know how to help you but have you seen this link before?
Yes, but it just reads a video into packet without any encoding and decoding, and writes the packet with function av_interleaved_write_frame
.
I have tried something like it (mp4 -> AVPacket -> flv - - - RTMP - - - > RTMP server
), it runs well.
Finally, it works.
Setting AV_CODEC_FLAG_GLOBAL_HEADER
to FormatContext->flags does not work. This results that encode_stream->codecpar->extradata
will be NULL. This actually causes pipe broken
.
Setting AV_CODEC_FLAG_GLOBAL_HEADER
to AVCodecContext->flags solves the problem, but it should be executed before opening the encoder.
Therefore, I adjust the code near the encoder
AVFormatContext *encoder_context;
avformat_alloc_output_context2(&encoder_context, nullptr, "flv", nullptr);
AVCodec *encoder_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
AVCodecContext *encoder = avcodec_alloc_context3(encoder_codec);
encoder->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
before opening the encoder
AVRational input_framerate = av_guess_frame_rate(decoder_context, decoder_stream, nullptr);
encoder->height = decoder->height;
encoder->width = decoder->width;
encoder->sample_aspect_ratio = decoder->sample_aspect_ratio;
encoder->pix_fmt = AV_PIX_FMT_YUV420P;
encoder->bit_rate = 2 * 100 * 1000;
encoder->rc_buffer_size = 4 * 1000 * 1000;
encoder->rc_max_rate = 2 * 1000 * 1000;
encoder->rc_min_rate = 2.5 * 1000 * 1000;
encoder->framerate = input_framerate;
encoder->time_base = av_inv_q(input_framerate);
av_opt_set(encoder->priv_data, "preset", "ultrafast", 0);
if (encoder_context->oformat->flags & AVFMT_GLOBALHEADER) encoder->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
avcodec_open2(encoder, encoder_codec, nullptr);
Here is the code:
#include <iostream>
extern "C" {
}
av_always_inline char *av_err2str(int errnum) { // static char str[AV_ERROR_MAX_STRING_SIZE]; // thread_local may be better than static in multi-thread circumstance thread_local char str[AV_ERROR_MAX_STRING_SIZE]; memset(str, 0, sizeof(str)); return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum); }
using namespace std;
int encode(AVFormatContext encoder_context, AVCodecContext encoder_codec_context, AVStream encoder_stream, AVStream decoder_stream, AVFrame *input_frame) { if (input_frame) input_frame->pict_type = AV_PICTURE_TYPE_NONE;
AVPacket *output_packet = av_packet_alloc();
int res = avcodec_send_frame(encoder_codec_context, input_frame);
while (res >= 0) {
res = avcodec_receive_packet(encoder_codec_context, output_packet);
if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) break;
else if (res < 0) return -1;
output_packet->stream_index = 0;
output_packet->duration =
encoder_stream->time_base.den / encoder_stream->time_base.num / decoder_stream->avg_frame_rate.num *
decoder_stream->avg_frame_rate.den;
output_packet->pos = -1;
av_packet_rescale_ts(output_packet, decoder_stream->time_base, encoder_stream->time_base);
res = av_interleaved_write_frame(encoder_context, output_packet);
if (res != 0) {
cout << av_err2str(res) << endl;
return -1;
}
}
av_packet_unref(output_packet);
av_packet_free(&output_packet);
return 0;
}
int main() { string input = "video.mp4"; string output = "rtmp://127.0.0.1/myapp/stream"; // string output = "a.flv";
// decoder
AVFormatContext *decoder_context = avformat_alloc_context();
avformat_open_input(&decoder_context, input.c_str(), nullptr, nullptr);
avformat_find_stream_info(decoder_context, nullptr);
AVStream *decoder_stream = decoder_context->streams[0];
AVCodec *decoder_codec = avcodec_find_decoder(decoder_stream->codecpar->codec_id);
AVCodecContext *decoder = avcodec_alloc_context3(decoder_codec);
avcodec_parameters_to_context(decoder, decoder_stream->codecpar);
avcodec_open2(decoder, decoder_codec, nullptr);
av_dump_format(decoder_context, 0, input.c_str(), 0);
// encoder
AVFormatContext *encoder_context;
avformat_alloc_output_context2(&encoder_context, nullptr, "flv", nullptr);
AVCodec *encoder_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
AVCodecContext *encoder = avcodec_alloc_context3(encoder_codec);
AVRational input_framerate = av_guess_frame_rate(decoder_context, decoder_stream, nullptr);
encoder->height = decoder->height;
encoder->width = decoder->width;
encoder->sample_aspect_ratio = decoder->sample_aspect_ratio;
encoder->pix_fmt = AV_PIX_FMT_YUV420P;
encoder->bit_rate = 2 * 100 * 1000;
encoder->rc_buffer_size = 4 * 1000 * 1000;
encoder->rc_max_rate = 2 * 1000 * 1000;
encoder->rc_min_rate = 2.5 * 1000 * 1000;
encoder->framerate = input_framerate;
encoder->time_base = av_inv_q(input_framerate);
av_opt_set(encoder->priv_data, "preset", "ultrafast", 0);
if (encoder_context->oformat->flags & AVFMT_GLOBALHEADER) encoder->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
avcodec_open2(encoder, encoder_codec, nullptr);
AVStream *encoder_stream = avformat_new_stream(encoder_context, nullptr);
avcodec_parameters_from_context(encoder_stream->codecpar, encoder);
encoder_stream->time_base = encoder->time_base;
encoder_stream->codecpar->codec_tag = 0;
if (!(encoder_context->oformat->flags & AVFMT_NOFILE)) {
avio_open2(&encoder_context->pb, output.c_str(), AVIO_FLAG_WRITE, nullptr, nullptr);
}
avformat_write_header(encoder_context, nullptr);
av_dump_format(encoder_context, 0, output.c_str(), 1);
AVFrame *input_frame = av_frame_alloc();
AVPacket *input_packet = av_packet_alloc();
while (av_read_frame(decoder_context, input_packet) >= 0) {
int res = avcodec_send_packet(decoder, input_packet);
if (res < 0) return res;
while (res >= 0) {
res = avcodec_receive_frame(decoder, input_frame);
if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) break;
else if (res < 0) return res;
if (res >= 0) {
if (encode(encoder_context, encoder, encoder_stream, decoder_stream, input_frame))
return -1;
}
av_frame_unref(input_frame);
}
}
if (encode(encoder_context, encoder, encoder_stream, decoder_stream, nullptr)) return -1;
av_write_trailer(encoder_context);
avformat_close_input(&decoder_context);
avformat_free_context(decoder_context);
avformat_free_context(encoder_context);
avcodec_free_context(&decoder);
avcodec_free_context(&encoder);
return 0;
}
I can't explain the reason, but it works according to my tests.
It works for me. I read the ffmpeg/docs/examples/muxing.c and it shows that the problem appears when the output formats want stream headers to be separate. Setting AV_CODEC_FLAG_GLOBAL_HEADER
to AVCodecContext->flags
can solve the problem.
Hi, thanks for this tutorial. It really help me a lot about the ffmpeg. But I met some problems in streaming a .mp4 video with RTMP based on the tutorial.
Target: I want to decode a .mp4 file, encode it with other codec and stream it with RTMP( flv).
mp4 -> AVPacket -> AVFrame -> a encoded new AVPacket -> flv - - - RTMP - - - > RTMP server
If I output the encoded video file to a local .flv file, everything runs perfect:
mp4 -> AVPacket -> AVFrame -> a encoded new AVPacket -> flv file
Or, If I just open a .mp4 file and stream it without decoding and re-encoding, it also runs well:mp4 -> AVPacket -> flv - - - RTMP - - - > RTMP server
However, when I change the output to a RTMP url, the function
av_interleaved_write_frame
always return "-32" which means "Broken pipe". I have tried a lot of different settings, but none of them works.I'm not sure if there is something I miss. Any help is appreciated.
Here is my code (I remove most of the error handling to make it more clear):