使用ffmpeg转换时,视频向左旋转90度

时间:2017-07-15 08:20:54

标签: ios video ffmpeg rotation

我开发了以下代码:

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度?

1 个答案:

答案 0 :(得分:1)

我通过添加:

将输入流的元数据指定为输出流的元数据来解决它
outAVFormatContext->metadata = fmt_ctx->metadata
outAVFormatContext->streams[video_stream_idx]->metadata=fmt_‌​ctx->streams[video_s‌​tream_idx]->metadata‌​