Last active
August 25, 2020 22:02
-
-
Save LinuxwitChdoCtOr/74c1721dd7688cf1d16509ea2a52d231 to your computer and use it in GitHub Desktop.
FFmpeg API 3.1 create file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <queue> | |
#include <functional> | |
#include <cstdint> | |
extern "C" | |
{ | |
#include <libavformat/avformat.h> | |
#include <libswscale/swscale.h> | |
#include <libavutil/imgutils.h> | |
#include <libavcodec/avcodec.h> | |
}; | |
/** | |
* Put a description of the AVERROR code errnum in errbuf. | |
* In case of failure the global variable errno is set to indicate the | |
* error. Even in case of failure av_strerror() will print a generic | |
* error message indicating the errnum provided to errbuf. | |
* | |
* @param errnum error code to describe | |
* @param errbuf buffer to which description is written | |
* @param errbuf_size the size in bytes of errbuf | |
* @return 0 on success, a negative value if a description for errnum | |
* cannot be found | |
* | |
int av_strerror(int errnum, char *errbuf, size_t errbuf_size); | |
*/ | |
#define STR(tok) #tok | |
#define ERRBUF_SIZE 256 | |
static char g_errbuf[ERRBUF_SIZE]; | |
static int g_errno = 0; | |
#define PRINT_AV_ERROR(x) \ | |
if ( errno ) g_errno = errno; \ | |
av_strerror( errno, g_errbuf, ERRBUF_SIZE ); \ | |
if ( g_errno ) \ | |
std::cerr << x << STR(:) << g_errbuf << std::endl; \ | |
else \ | |
std::cerr << x << STR(:UNKNOWN ERROR errno was NOT set ) << std::endl; \ | |
g_errno = 0; | |
int main( int argc, char* argv[] ) | |
{ | |
(void) argc; | |
(void) argv; | |
int rtn_val = 0; | |
std::string f( "enc.mp4" ); | |
AVDictionary * av_dict_opts = NULL; | |
AVCodec * av_encode_codec = NULL; | |
AVCodecContext * av_encode_codec_ctx = NULL; | |
AVFormatContext * av_out_fmt_ctx = NULL; | |
AVStream * video_st = NULL; | |
av_register_all(); | |
/// encoding profile | |
av_dict_set( &av_dict_opts, "preset", "losslesshp", 0 ); | |
av_dict_set( &av_dict_opts, "profile", "high", 0 ); | |
av_dict_set( &av_dict_opts, "rc", "vbr_minqp", 0 ); | |
av_dict_set( &av_dict_opts, "gpu", "1", 0 ); | |
av_encode_codec = avcodec_find_encoder( AV_CODEC_ID_H264 ); | |
if ( !av_encode_codec ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avcodec_find_encoder:" ); | |
return -1; | |
} | |
/** | |
* Allocate an AVFormatContext for an output format. | |
* avformat_free_context() can be used to free the context and | |
* everything allocated by the framework within it. | |
* | |
* @param *ctx is set to the created format context, or to NULL in | |
* case of failure | |
* @param oformat format to use for allocating the context, if NULL | |
* format_name and filename are used instead | |
* @param format_name the name of output format to use for allocating the | |
* context, if NULL filename is used instead | |
* @param filename the name of the filename to use for allocating the | |
* context, may be NULL | |
* @return >= 0 in case of success, a negative AVERROR code in case of | |
* failure | |
* | |
* int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, | |
* const char *format_name, const char *filename); | |
*/ | |
avformat_alloc_output_context2( &av_out_fmt_ctx, NULL, (char*)"mp4", f.c_str() ); | |
if ( !av_out_fmt_ctx ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avformat_alloc_output_context2:" ); | |
return -1; | |
} | |
/** | |
* Allocate an AVCodecContext and set its fields to default values. The | |
* resulting struct should be freed with avcodec_free_context(). | |
* | |
* @param codec if non-NULL, allocate private data and initialize defaults | |
* for the given codec. It is illegal to then call avcodec_open2() | |
* with a different codec. | |
* If NULL, then the codec-specific defaults won't be initialized, | |
* which may result in suboptimal default settings (this is | |
* important mainly for encoders, e.g. libx264). | |
* | |
* @return An AVCodecContext filled with default values or NULL on failure. | |
* | |
* AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); | |
*/ | |
av_encode_codec_ctx = avcodec_alloc_context3( av_encode_codec ); | |
if ( !av_encode_codec_ctx ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avcodec_alloc_context3:" ); | |
return -1; | |
} | |
av_encode_codec_ctx->codec_id = AV_CODEC_ID_H264; | |
av_encode_codec_ctx->bit_rate = 5e6; | |
av_encode_codec_ctx->width = 1024; /// \note multiple of 2 | |
av_encode_codec_ctx->height = 768; /// \note multiple of 2 | |
av_encode_codec_ctx->time_base = (AVRational) { 1, 60 }; //* 2; | |
av_encode_codec_ctx->gop_size = 15; // Intra frames per x P frames | |
av_encode_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // MUST DO NOT CHANGE nvenc required | |
/** | |
* Add a new stream to a media file. | |
* | |
* When demuxing, it is called by the demuxer in read_header(). If the | |
* flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also | |
* be called in read_packet(). | |
* | |
* When muxing, should be called by the user before avformat_write_header(). | |
* | |
* User is required to call avcodec_close() and avformat_free_context() to | |
* clean up the allocation by avformat_new_stream(). | |
* | |
* @param s media file handle | |
* @param c If non-NULL, the AVCodecContext corresponding to the new stream | |
* will be initialized to use this codec. This is needed for e.g. codec-specific | |
* defaults to be set, so codec should be provided if it is known. | |
* | |
* @return newly created stream or NULL on error. | |
* | |
* AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c); | |
*/ | |
video_st = avformat_new_stream( av_out_fmt_ctx, av_encode_codec ); | |
if ( !video_st ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avformat_new_stream:" ); | |
return -1; | |
} | |
/** | |
* Fill the parameters struct based on the values from the supplied codec | |
* context. Any allocated fields in par are freed and replaced with duplicates | |
* of the corresponding fields in codec. | |
* | |
* @return >= 0 on success, a negative AVERROR code on failure | |
*/ | |
if ( avcodec_parameters_from_context( video_st->codecpar, av_encode_codec_ctx ) < 0 ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avcodec_parameters_from_context:" ); | |
return rtn_val; | |
} | |
/** | |
* Initialize the AVCodecContext to use the given AVCodec. Prior to using this | |
* function the context has to be allocated with avcodec_alloc_context3(). | |
* | |
* The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), | |
* avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for | |
* retrieving a codec. | |
* | |
* @warning This function is not thread safe! | |
* | |
* @note Always call this function before using decoding routines (such as | |
* @ref avcodec_receive_frame()). | |
* | |
* @code | |
* avcodec_register_all(); | |
* av_dict_set(&opts, "b", "2.5M", 0); | |
* codec = avcodec_find_decoder(AV_CODEC_ID_H264); | |
* if (!codec) | |
* exit(1); | |
* | |
* context = avcodec_alloc_context3(codec); | |
* | |
* if (avcodec_open2(context, codec, opts) < 0) | |
* exit(1); | |
* @endcode | |
* | |
* @param avctx The context to initialize. | |
* @param codec The codec to open this context for. If a non-NULL codec has been | |
* previously passed to avcodec_alloc_context3() or | |
* for this context, then this parameter MUST be either NULL or | |
* equal to the previously passed codec. | |
* @param options A dictionary filled with AVCodecContext and codec-private options. | |
* On return this object will be filled with options that were not found. | |
* | |
* @return zero on success, a negative value on error | |
* @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), | |
* av_dict_set(), av_opt_find(). | |
* | |
* int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); | |
*/ | |
rtn_val = avcodec_open2( av_encode_codec_ctx, av_encode_codec, &av_dict_opts ); | |
if ( rtn_val < 0 ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avcodec_open2:" ); | |
return rtn_val; | |
} | |
if ( av_out_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER ) | |
av_out_fmt_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; | |
av_dump_format( av_out_fmt_ctx, 0, f.c_str(), 1 ); | |
if ( !( av_out_fmt_ctx->oformat->flags & AVFMT_NOFILE ) ) | |
{ | |
rtn_val = avio_open( &av_out_fmt_ctx->pb, f.c_str(), AVIO_FLAG_WRITE ); | |
if ( rtn_val < 0 ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avio_open:" ); | |
return rtn_val; | |
} | |
} | |
rtn_val = avformat_write_header( av_out_fmt_ctx, &av_dict_opts ); | |
if ( rtn_val < 0 ) | |
{ | |
PRINT_AV_ERROR( "ERROR:avformat_write_header:" ); | |
return rtn_val; | |
} | |
return rtn_val; | |
} | |
Current output
[mp4 @ 0x149aa60] dimensions not set
FYI
The call to avcodec_parameters_from_context
should appear after avcodec_open2
. Otherwise you may get a blank video.
Consult lines 408-449 in FFmpeg muxer example for reference.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
g++ -g -std=c++0x -Wall -Wextra -DDEBUG -DUSE_MAIN_DRIVER -I/usr/include/libdrm -I/usr/include/ffmpeg fileout.cpp -lavformat -lavcodec -lavutil -lswscale -lavdevice -lGLU -lGL -lX11 -lm -lrt -o fw