2017-06-23 94 views
2

的Windows 10 64, 的ffmpeg:3.1,预建的DLL的ffmpeg没有打电话avcodec_send_packet

绝对的初学者在这里。

我正在尝试一个非常基本的情况下解码来自视频文件的帧,但拼命地在每次尝试失败。最终的代码片段看起来是这样的:

#define __STDC_CONSTANT_MACROS 
extern "C" { 
#include<libavutil/avutil.h> 
#include<libavutil/imgutils.h> 
#include <libavformat/avformat.h> 
#include <libavcodec/avcodec.h> 
#include <libswscale/swscale.h> 
} 

#include <iostream> 


int main(int argc, char **argv) { 
    AVFormatContext* ctx_format = nullptr; 
    AVCodecContext* ctx_codec = nullptr; 
    AVCodec* codec = nullptr; 
    AVFrame* frame = av_frame_alloc(); 
    int stream_idx; 
    SwsContext* ctx_sws = nullptr; 
    const char* fin = argv[1]; 
    AVStream *vid_stream = nullptr; 
    AVPacket* pkt = av_packet_alloc(); 

    av_register_all(); 

    if (int ret = avformat_open_input(&ctx_format, fin, nullptr, nullptr) != 0) { 
     std::cout << 1 << std::endl; 
     return ret; 
    } 
    if (avformat_find_stream_info(ctx_format, nullptr) < 0) { 
     std::cout << 2 << std::endl; 
     return -1; // Couldn't find stream information 
    } 
    av_dump_format(ctx_format, 0, fin, false); 

    for (int i = 0; i < ctx_format->nb_streams; i++) 
     if (ctx_format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { 
      stream_idx = i; 
      vid_stream = ctx_format->streams[i]; 
      break; 
    } 
    if (vid_stream == nullptr) { 
     std::cout << 4 << std::endl; 
     return -1; 
    } 

    codec = avcodec_find_decoder(vid_stream->codecpar->codec_id); 
    if (!codec) { 
     fprintf(stderr, "codec not found\n"); 
     exit(1); 
    } 
    ctx_codec = avcodec_alloc_context3(codec); 

    if(avcodec_parameters_to_context(ctx_codec, vid_stream->codecpar)<0) 
     std::cout << 512; 
    if (avcodec_open2(ctx_codec, codec, nullptr)<0) { 
     std::cout << 5; 
     return -1; 
    } 

    //av_new_packet(pkt, pic_size); 

    while(av_read_frame(ctx_format, pkt) >= 0){ 
     int ret = avcodec_send_packet(ctx_codec, pkt); 
     if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
      std::cout << "avcodec_send_packet: " << ret << std::endl; 
      break; 
     } 
     if (pkt->stream_index == stream_idx) { 
      while (ret >= 0) { 
       ret = avcodec_receive_frame(ctx_codec, frame); 
       if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
        //std::cout << "avcodec_receive_frame: " << ret << std::endl; 
        break; 
       } 
       std::cout << "frame: " << ctx_codec->frame_number << std::endl; 
      } 
     } 
     av_packet_unref(pkt); 
    } 

    avformat_close_input(&ctx_format); 
    av_packet_unref(pkt); 
    avcodec_free_context(&ctx_codec); 
    avformat_free_context(ctx_format); 
    return 0; 
} 

它基本上是由它的默认值留下的一切,并尝试从中读取数据包和解码帧。 avcodec_send_packet在while循环的第一轮或第二轮呼叫中总是返回负值。

输出对于FLV

> .\streamer_test.exe .\SampleVideo_360x240_5mb.flv 
Input #0, flv, from '.\SampleVideo_360x240_5mb.flv': 
    Metadata: 
    encoder   : Lavf53.24.2 
    Duration: 00:00:53.32, start: 0.000000, bitrate: 787 kb/s 
    Stream #0:0: Audio: aac (LC), 48000 Hz, 5.1, fltp, 384 kb/s 
    Stream #0:1: Video: flv1, yuv420p, 320x240, 500 kb/s, 1k fps, 25 tbr, 1k tbn 
frame: 1 
[flv @ 000001545edb66c0] Bad picture start code 
[flv @ 000001545edb66c0] header damaged 
avcodec_send_packet: -1094995529 

输出针对MP4

> .\streamer_test.exe .\SampleVideo_360x240_10mb.mp4 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '.\SampleVideo_360x240_10mb.mp4': 
    Metadata: 
    major_brand  : isom 
    minor_version : 512 
    compatible_brands: isomiso2avc1mp41 
    creation_time : 1970-01-01T00:00:00.000000Z 
    encoder   : Lavf53.24.2 
    Duration: 00:02:05.95, start: 0.000000, bitrate: 669 kb/s 
    Stream #0:0(und): Video: h264 (Main) (avc1/0x31637661), yuv420p, 320x240 [SAR 1:1 DAR 4:3], 282 kb/s, 15 fps, 15 t 
br, 15360 tbn, 30 tbc (default) 
    Metadata: 
     creation_time : 1970-01-01T00:00:00.000000Z 
     handler_name : VideoHandler 
    Stream #0:1(und): Audio: aac (LC) (mp4a/0x6134706D), 48000 Hz, 5.1, fltp, 383 kb/s (default) 
    Metadata: 
     creation_time : 1970-01-01T00:00:00.000000Z 
     handler_name : SoundHandler 
[h264 @ 000002e2446a6cc0] Invalid NAL unit size (17191968 > 1007). 
[h264 @ 000002e2446a6cc0] Error splitting the input into NAL units. 
avcodec_send_packet: -1094995529 

输出为MKV

> .\streamer_test.exe .\SampleVideo_1280x720_2mb.mkv 
Input #0, matroska,webm, from '.\SampleVideo_1280x720_2mb.mkv': 
    Metadata: 
    ENCODER   : Lavf53.24.2 
    Duration: 00:00:10.65, bitrate: 1575 kb/s 
    Stream #0:0: Video: mpeg4 (Simple Profile), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 25 tbc (de 
fault) 
    Stream #0:1: Audio: aac (LC), 48000 Hz, 5.1, fltp (default) 
frame: 1 
[mpeg4 @ 000001166798ede0] header damaged 
avcodec_send_packet: -1 

因此,我想在avcodec_send_packet的调用中肯定会出现问题,但无法找出缺少的内容。关于原因的任何想法?非常感谢您的帮助!

回答

4

电话av_read_frame将返回音频/视频流,您需要使用不同的AVCodecContext来处理它们。

因为你avcodec_send_packet发送音频流,但你的 AVCodecContext是视频流,你得到了错误。

看来你只对视频流感兴趣。

while(av_read_frame(ctx_format, pkt) >= 0){ 
    int ret = avcodec_send_packet(ctx_codec, pkt); 
    if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
     std::cout << "avcodec_send_packet: " << ret << std::endl; 
     break; 
    } 
    if (pkt->stream_index == stream_idx) { 
     while (ret >= 0) { 
      ret = avcodec_receive_frame(ctx_codec, frame); 
      if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
       //std::cout << "avcodec_receive_frame: " << ret << std::endl; 
       break; 
      } 
      std::cout << "frame: " << ctx_codec->frame_number << std::endl; 
     } 
    } 
    av_packet_unref(pkt); 
} 

更改您的代码下面的工作。

while(av_read_frame(ctx_format, pkt) >= 0){ 
    if (pkt->stream_index == stream_idx) { 
     int ret = avcodec_send_packet(ctx_codec, pkt); 
     if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
      std::cout << "avcodec_send_packet: " << ret << std::endl; 
      break; 
     } 
     while (ret >= 0) { 
      ret = avcodec_receive_frame(ctx_codec, frame); 
      if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 
       //std::cout << "avcodec_receive_frame: " << ret << std::endl; 
       break; 
      } 
      std::cout << "frame: " << ctx_codec->frame_number << std::endl; 
     } 
    } 
    av_packet_unref(pkt); 
} 

当解码利用FFMPEG,记得调用avcodec_send_packet/avcodec_receive_frame在一对为不同的流。

+0

谢谢!它现在像一个魅力工作! – Gizak

+0

我花了很多时间让这个库工作,而不使用过时的函数,这应该被添加到ffmpeg的例子!完美的作品。 –