2
轉換時通過90度的左我開發了下面的代碼:視頻旋轉到使用的ffmpeg
extern "C"
{
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfiltergraph.h>
#include <libswscale/swscale.h>
}
#include <stdio.h>
static AVFormatContext *fmt_ctx = NULL;
static int frame_index = 0;
static int j = 0, nbytes=0;
uint8_t *video_outbuf = NULL;
static AVPacket *pAVPacket=NULL;
static int value=0;
static AVFrame *pAVFrame=NULL;
static AVFrame *outFrame=NULL;
static AVStream *video_st=NULL;
static AVFormatContext *outAVFormatContext=NULL;
static AVCodec *outAVCodec=NULL;
static AVOutputFormat *output_format=NULL;
static AVCodecContext *video_dec_ctx = NULL, *audio_dec_ctx;
static AVCodecContext *outAVCodecContext=NULL;
static int width, height;
static enum AVPixelFormat pix_fmt;
static AVStream *video_stream = NULL, *audio_stream = NULL;
static const char *src_filename = NULL;
static const char *video_dst_filename = NULL;
static const char *audio_dst_filename = NULL;
static FILE *video_dst_file = NULL;
static FILE *audio_dst_file = NULL;
static uint8_t *video_dst_data[4] = {NULL};
static int video_dst_linesize[4];
static int video_dst_bufsize;
static int video_stream_idx = -1, audio_stream_idx = -1;
static AVPacket *pkt=NULL;
static AVPacket *pkt1=NULL;
static AVFrame *frame = NULL;
//static AVPacket pkt;
static int video_frame_count = 0;
static int audio_frame_count = 0;
static int refcount = 0;
AVCodec *codec;
static struct SwsContext *sws_ctx;
AVCodecContext *c= NULL;
int i, out_size, size, x, y, outbuf_size;
AVFrame *picture;
uint8_t *outbuf, *picture_buf;
int video_outbuf_size;
int w, h;
AVPixelFormat pixFmt;
uint8_t *data[4];
int linesize[4];
static int open_codec_context(int *stream_idx,
AVCodecContext **dec_ctx, AVFormatContext
*fmt_ctx, enum AVMediaType type)
{
int ret, stream_index;
AVStream *st;
AVCodec *dec = NULL;
AVDictionary *opts = NULL;
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
if (ret < 0) {
printf("Could not find %s stream in input file '%s'\n",
av_get_media_type_string(type), src_filename);
return ret;
} else {
stream_index = ret;
st = fmt_ctx->streams[stream_index];
/* find decoder for the stream */
dec = avcodec_find_decoder(st->codecpar->codec_id);
if (!dec) {
printf("Failed to find %s codec\n",
av_get_media_type_string(type));
return AVERROR(EINVAL);
}
/* Allocate a codec context for the decoder */
*dec_ctx = avcodec_alloc_context3(dec);
if (!*dec_ctx) {
printf("Failed to allocate the %s codec context\n",
av_get_media_type_string(type));
return AVERROR(ENOMEM);
}
/* Copy codec parameters from input stream to output codec context */
if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
printf("Failed to copy %s codec parameters to decoder context\n",
av_get_media_type_string(type));
return ret;
}
/* Init the decoders, with or without reference counting */
av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
printf("Failed to open %s codec\n",
av_get_media_type_string(type));
return ret;
}
*stream_idx = stream_index;
}
return 0;
}
int main (int argc, char **argv)
{
int ret = 0, got_frame;
src_filename = argv[1];
video_dst_filename = argv[2];
audio_dst_filename = argv[3];
av_register_all();
avcodec_register_all();
printf("Registered all\n");
/* open input file, and allocate format context */
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
printf("Could not open source file %s\n", src_filename);
exit(1);
}
/* retrieve stream information */
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
printf("Could not find stream information\n");
exit(1);
}
if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx,
AVMEDIA_TYPE_VIDEO) >= 0) {
video_stream = fmt_ctx->streams[video_stream_idx];
avformat_alloc_output_context2(&outAVFormatContext, NULL, NULL,
video_dst_filename);
if (!outAVFormatContext)
{
printf("\n\nError : avformat_alloc_output_context2()");
return -1;
}
}
if (open_codec_context(&audio_stream_idx, &audio_dec_ctx, fmt_ctx,
AVMEDIA_TYPE_AUDIO) >= 0) {
audio_stream = fmt_ctx->streams[audio_stream_idx];
audio_dst_file = fopen(audio_dst_filename, "wb");
if (!audio_dst_file) {
printf("Could not open destination file %s\n", audio_dst_filename);
ret = 1;
goto end;
}
}
/* dump input information to stderr */
av_dump_format(fmt_ctx, 0, src_filename, 0);
if (!audio_stream && !video_stream) {
printf("Could not find audio or video stream in the input, aborting\n");
ret = 1;
goto end;
}
output_format = av_guess_format(NULL, video_dst_filename, NULL);
if(!output_format)
{
printf("\n\nError : av_guess_format()");
return -1;
}
video_st = avformat_new_stream(outAVFormatContext ,NULL);
if(!video_st)
{
printf("\n\nError : avformat_new_stream()");
return -1;
}
outAVCodecContext = avcodec_alloc_context3(outAVCodec);
if(!outAVCodecContext)
{
printf("\n\nError : avcodec_alloc_context3()");
return -1;
}
outAVCodecContext = video_st->codec;
outAVCodecContext->codec_id = AV_CODEC_ID_MPEG4;// AV_CODEC_ID_MPEG4; //
AV_CODEC_ID_H264 // AV_CODEC_ID_MPEG1VIDEO
outAVCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
outAVCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
outAVCodecContext->bit_rate = 400000; // 2500000
outAVCodecContext->width = 1920;
//outAVCodecContext->width = 500;
outAVCodecContext->height = 1080;
//outAVCodecContext->height = 500;
outAVCodecContext->gop_size = 3;
outAVCodecContext->max_b_frames = 2;
outAVCodecContext->time_base.num = 1;
outAVCodecContext->time_base.den = 30; // 15fps
if (outAVCodecContext->codec_id == AV_CODEC_ID_H264)
{
av_opt_set(outAVCodecContext->priv_data, "preset", "slow", 0);
}
outAVCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
if(!outAVCodec)
{
printf("\n\nError : avcodec_find_encoder()");
return -1;
}
/* Some container formats (like MP4) require global headers to be
present
Mark the encoder so that it behaves accordingly. */
if (outAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER)
{
outAVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
value = avcodec_open2(outAVCodecContext, outAVCodec, NULL);
if(value < 0)
{
printf("\n\nError : avcodec_open2()");
return -1;
}
/* create empty video file */
if (!(outAVFormatContext->flags & AVFMT_NOFILE))
{
if(avio_open2(&outAVFormatContext->pb , video_dst_filename,
AVIO_FLAG_WRITE ,NULL, NULL) < 0)
{
printf("\n\nError : avio_open2()");
}
}
if(!outAVFormatContext->nb_streams)
{
printf("\n\nError : Output file dose not contain any stream");
return -1;
}
/* imp: mp4 container or some advanced container file required header
information*/
value = avformat_write_header(outAVFormatContext , NULL);
if(value < 0)
{
printf("\n\nError : avformat_write_header()");
return -1;
}
printf("\n\nOutput file information :\n\n");
av_dump_format(outAVFormatContext , 0 ,video_dst_filename ,1);
int flag;
int frameFinished;
value = 0;
pAVPacket = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet(pAVPacket);
pAVFrame = av_frame_alloc();
if(!pAVFrame)
{
printf("\n\nError : av_frame_alloc()");
return -1;
}
outFrame = av_frame_alloc();//Allocate an AVFrame and set its fields to
default values.
if(!outFrame)
{
printf("\n\nError : av_frame_alloc()");
return -1;
}
nbytes = av_image_get_buffer_size(outAVCodecContext-
>pix_fmt,outAVCodecContext->width,outAVCodecContext->height,32);
video_outbuf = (uint8_t*)av_malloc(nbytes);
if(video_outbuf == NULL)
{
printf("\n\nError : av_malloc()");
}
value = av_image_fill_arrays(outFrame->data, outFrame->linesize,
video_outbuf , AV_PIX_FMT_YUV420P, outAVCodecContext-
>width,outAVCodecContext->height,1); // returns : the size in bytes
required for src
if(value < 0)
{
printf("\n\nError : av_image_fill_arrays()");
}
SwsContext* swsCtx_ ;
// Allocate and return swsContext.
// a pointer to an allocated context, or NULL in case of error
// Deprecated : Use sws_getCachedContext() instead.
swsCtx_ = sws_getContext(video_dec_ctx->width,
video_dec_ctx->height,
video_dec_ctx->pix_fmt,
video_dec_ctx->width,
video_dec_ctx->height,
video_dec_ctx->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
AVPacket outPacket;
int got_picture;
while(av_read_frame(fmt_ctx , pAVPacket) >= 0)
{
if(pAVPacket->stream_index == video_stream_idx)
{
value = avcodec_decode_video2(video_dec_ctx , pAVFrame ,
&frameFinished , pAVPacket);
if(value < 0)
{
printf("Error : avcodec_decode_video2()");
}
if(frameFinished)// Frame successfully decoded :)
{
sws_scale(swsCtx_, pAVFrame->data, pAVFrame-
>linesize,0, video_dec_ctx->height, outFrame->data,outFrame->linesize);
// sws_scale(swsCtx_, pAVFrame->data, pAVFrame-
>linesize,0, video_dec_ctx->height, outFrame->data,outFrame->linesize);
av_init_packet(&outPacket);
outPacket.data = NULL; // packet data will be
allocated by the encoder
outPacket.size = 0;
avcodec_encode_video2(outAVCodecContext ,
&outPacket ,outFrame , &got_picture);
if(got_picture)
{
if(outPacket.pts != AV_NOPTS_VALUE)
outPacket.pts =
av_rescale_q(outPacket.pts, video_st->codec->time_base, video_st-
>time_base);
if(outPacket.dts != AV_NOPTS_VALUE)
outPacket.dts =
av_rescale_q(outPacket.dts, video_st->codec->time_base, video_st-
>time_base);
printf("Write frame %3d (size= %2d)\n",
j++, outPacket.size/1000);
if(av_write_frame(outAVFormatContext ,
&outPacket) != 0)
{
printf("\n\nError :
av_write_frame()");
}
av_packet_unref(&outPacket);
} // got_picture
av_packet_unref(&outPacket);
} // frameFinished
}
}// End of while-loop
value = av_write_trailer(outAVFormatContext);
if(value < 0)
{
printf("\n\nError : av_write_trailer()");
}
//THIS WAS ADDED LATER
av_free(video_outbuf);
end:
avcodec_free_context(&video_dec_ctx);
avcodec_free_context(&audio_dec_ctx);
avformat_close_input(&fmt_ctx);
if (video_dst_file)
fclose(video_dst_file);
if (audio_dst_file)
fclose(audio_dst_file);
//av_frame_free(&frame);
av_free(video_dst_data[0]);
return ret < 0;
}
問題的上述代碼是,它旋轉的視頻由90度到左。
Snapshot of video given as input to above program
Snapshot of output video. It is rotated by 90 degree to left.
使用以下命令我編譯的程序:其鏈接使用以下命令
g++ -D__STDC_CONSTANT_MACROS -Wall -g ScreenRecorder.cpp -I/home/harry/Documents/compressor/ffmpeg-3.3/ -I/root/android-ndk-r14b/platforms/android-21/arch-x86_64/usr/include/ -c -o ScreenRecorder.o -w
和:
g++ -Wall -g ScreenRecorder.o -I/home/harry/Documents/compressor/ffmpeg-3.3/ -I/root/android-ndk-r14b/platforms/android-21/arch-x86_64/usr/include/ -L/usr/lib64 -L/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/ -L/home/harry/Documents/compressor/ffmpeg-3.3/ffmpeg-build -L/root/android-ndk-r14b/platforms/android-21/arch-x86_64/usr/lib64 -o ScreenRecorder.exe -lavformat -lavcodec -lavutil -lavdevice -lavfilter -lswscale -lx264 -lswresample -lm -lpthread -ldl -lstdc++ -lc -lrt
方案是使用下面的命令正在運行:
./ScreenRecorder.exe vertical.MOV videoH.mp4 audioH.mp3
注意: - 源視頻取自iphone並且是.mov格式。 - 輸出視頻正在存儲在.mp4文件中。
誰能告訴我爲什麼它旋轉視頻90度?
有一兩件事我注意到轉儲如下所示:
Duration: 00:00:06.04, start: 0.000000, bitrate: 17087 kb/s
Stream #0:0(und): Video: h264 (High) (avc1/0x31637661), yuv420p(tv, bt709), 1920x1080, 17014 kb/s, 29.98 fps, 29.97 tbr, 600 tbn, 1200 tbc (default)
Metadata:
rotate : 90
creation_time : 2017-07-09T10:56:42.000000Z
handler_name : Core Media Data Handler
encoder : H.264
Side data:
displaymatrix: rotation of -90.00 degrees
它說displaymatrix: rotation of -90.00 degrees
。它是否負責旋轉視頻90度?
我解決它自己。謝謝你們。 :) –
你應該通過點擊下面的按鈕來回答你自己的問題。這將有助於其他人也有類似的問題。 – slhck
哦對不起...我通過添加'outAVFormatContext-> metadata = fmt_ctx-> metadata將輸入流的元數據分配爲輸出流的元數據; outAVFormatContext-> streams [video_stream_idx] - > metadata = fmt_ctx-> streams [video_stream_idx] - > metadata;' –