2017-07-15 164 views
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度?

+0

我解决它自己。谢谢你们。 :) –

+0

你应该通过点击下面的按钮来回答你自己的问题。这将有助于其他人也有类似的问题。 – slhck

+0

哦对不起...我通过添加'outAVFormatContext-> metadata = fmt_ctx-> metadata将输入流的元数据分配为输出流的元数据; outAVFormatContext-> streams [video_stream_idx] - > metadata = fmt_ctx-> streams [video_stream_idx] - > metadata;' –

回答

0

我解决它通过分配输入流作为输出流的所述元数据的元数据的添加:

outAVFormatContext->metadata = fmt_ctx->metadata 
outAVFormatContext->streams[video_stream_idx]->metadata=fmt_‌​ctx->streams[video_s‌​tream_idx]->metadata‌​