zoukankan      html  css  js  c++  java
  • ffmpeg jpeg图片播放失败之问题排查

    播放jpeg时,avformat_find_stream_info出现以下问题,排查:

    [jpeg_pipe @ 0x146a80] Could not find codec parameters for stream 0 (Video: mjpeg, none(bt470bg/unknown/unknown)): unspecified size
    Consider increasing the value for the 'analyzeduration' and 'probesize' options

     1. 打印开启的codec信息,发现mjpeg codec已经开启

    AVCodec * av_codec = av_codec_next(NULL);
        while(av_codec)
        {
            printf("codec name:%s
    ", av_codec->name);
            av_codec = av_codec_next(av_codec);
        }
    

    检查demux的支持哪些format状况

    AVInputFormat *av_i = av_iformat_next(NULL);
    while(av_i)
    {
        printf("name:%s
    ", av_i->name);
        av_i = av_iformat_next(av_i);
    }

    2. 阅读avformat_find_stream_info代码,在里面加log确认卡住的地方

    发现has_codec_parameters()check失败导致,然后就追查avctx->width为何没有赋值。

      

    3.发现read_frame_internal()调用出错,导致没有try decode。然后trace flow

    4.iformat->read_packet(),format已经知道为jpeg_pipe,可惜搜不到相应的demuxer。

    好像是这里,可惜搜不到函数。wav有ff_wav_demuxer,但是image_jpeg_pipe没有ff_image_jpeg_pipe的变量定义。

    此时你已经知道自己掉坑里了,没事,习惯就好了。

    void av_register_all(void)
    {
    //...
        /* image demuxers */
        REGISTER_DEMUXER (IMAGE_JPEG_PIPE,       image_jpeg_pipe);
        REGISTER_DEMUXER (IMAGE_JPEGLS_PIPE,     image_jpegls_pipe);
    //...
    }

    最后发现定义在img2dec.c中,别问我怎么找到的,_pipe这个字符串不是很特别嘛,虽然也很多。。。

    #define IMAGEAUTO_DEMUXER(imgname, codecid)
    static const AVClass imgname ## _class = {
        .class_name = AV_STRINGIFY(imgname) " demuxer",
        .item_name  = av_default_item_name,
        .option     = ff_img_options,
        .version    = LIBAVUTIL_VERSION_INT,
    };
    AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {
        .name           = AV_STRINGIFY(imgname) "_pipe",
        .long_name      = NULL_IF_CONFIG_SMALL("piped " AV_STRINGIFY(imgname) " sequence"),
        .priv_data_size = sizeof(VideoDemuxData),
        .read_probe     = imgname ## _probe,
        .read_header    = ff_img_read_header,
        .read_packet    = ff_img_read_packet,
        .priv_class     = & imgname ## _class,
        .flags          = AVFMT_GENERIC_INDEX, 
        .raw_codec_id   = codecid,
    };
    
    IMAGEAUTO_DEMUXER(bmp,     AV_CODEC_ID_BMP)
    IMAGEAUTO_DEMUXER(dds,     AV_CODEC_ID_DDS)
    IMAGEAUTO_DEMUXER(dpx,     AV_CODEC_ID_DPX)
    IMAGEAUTO_DEMUXER(exr,     AV_CODEC_ID_EXR)
    IMAGEAUTO_DEMUXER(j2k,     AV_CODEC_ID_JPEG2000)
    IMAGEAUTO_DEMUXER(jpeg,    AV_CODEC_ID_MJPEG)
    IMAGEAUTO_DEMUXER(jpegls,  AV_CODEC_ID_JPEGLS)
    IMAGEAUTO_DEMUXER(pictor,  AV_CODEC_ID_PICTOR)
    IMAGEAUTO_DEMUXER(png,     AV_CODEC_ID_PNG)
    IMAGEAUTO_DEMUXER(qdraw,   AV_CODEC_ID_QDRAW)
    IMAGEAUTO_DEMUXER(sgi,     AV_CODEC_ID_SGI)
    IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST)
    IMAGEAUTO_DEMUXER(tiff,    AV_CODEC_ID_TIFF)
    IMAGEAUTO_DEMUXER(webp,    AV_CODEC_ID_WEBP)

    4. 进入ff_img_read_packet分析,这个流程图就不画了(因为网上没搜到)

    原因很简单我的avio不能seek,所以size[0]为-38,然后packet new不出来,然后就少了一个螺丝钉,然后就打仗打输了。

    所以问题点就是我的avio不能seek?what?

        } else {
            f[0] = s1->pb;
            if (avio_feof(f[0]) && s->loop && s->is_pipe)
                avio_seek(f[0], 0, SEEK_SET);
            if (avio_feof(f[0]))
                return AVERROR_EOF;
            if (s->frame_size > 0) {
                size[0] = s->frame_size;
            } else if (!s1->streams[0]->parser) {
                size[0] = avio_size(s1->pb);//执行到这咯,size[0]为-38
            } else {
                size[0] = 4096;
            }
        }
        //这个报错了,res为-22
        res = av_new_packet(pkt, size[0] + size[1] + size[2]);

    5. avio不能seek是由于,这个avio是定制的(说白了,自己写的,自己给自己挖坑)

    AVIOContext *avio_alloc_context(
                      unsigned char *buffer,
                      int buffer_size,
                      int write_flag,
                      void *opaque,
                      int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                      int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                      int64_t (*seek)(void *opaque, int64_t offset, int whence))
    
    //...
        avio = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                      0, &bd, &read_bs, NULL, NULL);

    6.当然如果故事就这样结束了,我也会很happy。同样的图片解码的code,在另一个平台用得好好的,但在这个平台却非要实现一个seek不可?

    7.然后在另一个ok的平台上调试,发现走的flow不一样。

    在另一个平台上是有相应的parser的。

        } else {
            f[0] = s1->pb;
            if (avio_feof(f[0]) && s->loop && s->is_pipe)
                avio_seek(f[0], 0, SEEK_SET);
            if (avio_feof(f[0]))
                return AVERROR_EOF;
            if (s->frame_size > 0) {
                size[0] = s->frame_size;
            } else if (!s1->streams[0]->parser) {
                size[0] = avio_size(s1->pb);
            } else {
                size[0] = 4096;//我是走这的,笨蛋
            }
        }
    
        res = av_new_packet(pkt, size[0] + size[1] + size[2]);

    8. 最终原因很简单,该平台的mjpeg的parse没有开....

    9.找到原因就结束了吗?!当然不是,我们还要认真反思。(被老板发现,一分钟就可以开好的配置,具体调试了一天,分分钟被抽死)

    第一步就检查了配置,而且是在代码里加code,这样太不方便了。

    ./configure就会打印到底开了哪些,如果一开始就仔细检查是不是就不用这么花时间调试了。(假装自己是老板,严厉呵斥该码农)

    Enabled programs:
    ffmpeg             ffprobe          ffserver
    
    External libraries:
    iconv             zlib
    
    External libraries providing hardware acceleration:
    cuda             cuvid              nvenc
    
    Libraries:
    avcodec             avdevice          avfilter           avformat            avutil             swresample              swscale
    
    Enabled decoders:
    aac             adpcm_yamaha          cpia               fourxm            mdec             on2avc              pjs               srt            vp3
    
    Enabled encoders:
    a64multi         ass              ffv1               mjpeg            pcm_alaw             pcm_s64be              prores_aw               srt            vorbis
    a64multi5
    
    Enabled parsers:
    aac             cavsvideo          dpx               dvdsub            h261             mjpeg              mpegvideo               rv30            vorbis
    aac_latm

    10. 还有第十步,不说了,今晚又得加班了...

  • 相关阅读:
    C# Asp.NET实现上传大文件(断点续传)
    asp.net mvc大文件上传、断点续传功能。
    JS&ASPDotNet_大文件上传问题
    javascript之大文件分段上传、断点续传(一)
    使用JS实现可断点续传的文件上传方案
    js+php大文件分片上传
    文件/大文件上传功能实现(JS+PHP)全过程
    js实现大文件分片上传的方法
    [每天一个Linux小技巧] 查看时钟源精度
    Linux
  • 原文地址:https://www.cnblogs.com/ranson7zop/p/7061530.html
Copyright © 2011-2022 走看看