Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/103.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios FFMPEG在解码流时对每个帧发出请求,性能较慢_Ios_Ffmpeg_Libavcodec_Libav - Fatal编程技术网

Ios FFMPEG在解码流时对每个帧发出请求,性能较慢

Ios FFMPEG在解码流时对每个帧发出请求,性能较慢,ios,ffmpeg,libavcodec,libav,Ios,Ffmpeg,Libavcodec,Libav,我在播放从iPhone拍摄的MOV摄像机文件时遇到问题。我的FFMPEG实现在播放大多数文件格式时没有问题,此问题仅适用于相机拍摄的MOV 当尝试打开文件时,我可以在日志中看到,在发出新请求之前,会发出许多请求,每个请求仅解码一帧,这导致视频缓冲速度非常慢。 大约需要一分钟来缓冲几秒钟的视频 另一件需要提及的事情是,在本地播放同一个有问题的文件时没有出现问题。问题是当尝试在流媒体中解码时 我使用cocoapods mobile ffmpeg https 4.2在Xcode 11、iOS SDK

我在播放从iPhone拍摄的MOV摄像机文件时遇到问题。我的FFMPEG实现在播放大多数文件格式时没有问题,此问题仅适用于相机拍摄的MOV

当尝试打开文件时,我可以在日志中看到,在发出新请求之前,会发出许多请求,每个请求仅解码一帧,这导致视频缓冲速度非常慢。 大约需要一分钟来缓冲几秒钟的视频

另一件需要提及的事情是,在本地播放同一个有问题的文件时没有出现问题。问题是当尝试在流媒体中解码时

我使用cocoapods mobile ffmpeg https 4.2在Xcode 11、iOS SDK 13上编译了我的代码

下面是我的代码的粗略表示,它相当标准:

  • 以下是我打开AVFormatContext的方式:
  • 打开解码器后的日志:

    // [tls] Request is made here
    // [tls] Request response headers are here
    Probing mov,mp4,m4a,3gp,3g2,mj2 score:100 size:2048
    Probing mp3 score:1 size:2048
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] type:'ftyp' parent:'root' sz: 20 8 23077123
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] ISO: File Type Major Brand: qt  
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] type:'wide' parent:'root' sz: 8 28 23077123
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] type:'mdat' parent:'root' sz: 23066642 36 23077123
    // [tls] Request is made here
    // [tls] Request response headers are here
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 0, sample 4, dts 133333
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 1, sample 48, dts 1114558
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 2, sample 1, dts 2666667
    [h264 @ 0x116080200] nal_unit_type: 1(Coded slice of a non-IDR picture), nal_ref_idc: 1
    // [tls] Request is made here
    // [tls] Request response headers are here
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 0, sample 4, dts 133333
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 1, sample 48, dts 1114558
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x115918e00] stream 2, sample 1, dts 2666667
    [h264 @ 0x116080200] nal_unit_type: 1(Coded slice of a non-IDR picture), nal_ref_idc: 1
    // [tls] Request is made here
    // [tls] Request response headers are here
    // ...
    
    这些是我在日志中发现的一些警告

    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] interrupted
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] stream 0: start_time: 0.000 duration: 11.833
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] stream 1: start_time: 0.000 duration: 11.832
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] stream 2: start_time: 0.000 duration: 11.833
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] stream 3: start_time: 0.000 duration: 11.833
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] format: start_time: 0.000 duration: 11.833 bitrate=15601 kb/s
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] Could not find codec parameters for stream 0 (Video: h264, 1 reference frame (avc1 / 0x31637661), none(bt709, left), 1920x1080, 1/1200, 15495 kb/s): unspecified pixel format
    Consider increasing the value for the 'analyzeduration' and 'probesize' options
    [mov,mp4,m4a,3gp,3g2,mj2 @ 0x11c030800] After avformat_find_stream_info() pos: 23077123 bytes read:16293 seeks:1 frames:0
    
    另外,当调用avformat_open_input(…)时,在返回之前会发出2个GET请求。 请注意“探测mp3分数:1”,它没有显示其他MOV文件或任何其他文件

    我尝试过不同版本的ffmpeg,我尝试过处理流的延迟,我尝试过删除我的自定义中断回调,但没有任何效果

    该代码与我测试过的任何其他视频(mp4、mkv、avi)都可以很好地配合使用

    测试文件的元数据:

    Metadata:
        major_brand     : qt  
        minor_version   : 0
        compatible_brands: qt  
        creation_time   : 2019-04-14T08:17:03.000000Z
        com.apple.quicktime.make: Apple
        com.apple.quicktime.model: iPhone 7
        com.apple.quicktime.software: 12.2
        com.apple.quicktime.creationdate: 2019-04-14T11:17:03+0300
      Duration: 00:00:16.83, bitrate: N/A
        Stream #0:0(und), 0, 1/600: Video: h264, 1 reference frame (avc1 / 0x31637661), none(bt709), 1920x1080 (0x0), 0/1, 15301 kb/s, 30 fps, 30 tbr, 600 tbn (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Video
          encoder         : H.264
        Stream #0:1(und), 0, 1/44100: Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, 100 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Audio
        Stream #0:2(und), 0, 1/600: Data: none (mebx / 0x7862656D), 0/1, 0 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Metadata
        Stream #0:3(und), 0, 1/600: Data: none (mebx / 0x7862656D), 0/1, 0 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Metadata
    
    我找到了一个解决方案(差不多):

    将AVFormatContext的io_open回调设置为您自己的函数,然后在调用该函数时,在调用默认io_open后,更改缓冲区大小

    static int (*IO_OPEN_DEFAULT)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options);
    
    int IO_OPEN_OVERRIDE(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options) {
        int result = IO_OPEN_DEFAULT(s, pb, url, flags, options);
        pb[0]->buffer_size = 41239179;
        return result;
    }
    
    这解决了问题。您将其设置为的值通常非常大(20到40MB)。打开格式上下文时,您可以从第二个网络请求字节范围中获取该值(第一个网络请求以字节范围0-*发出,然后第二个网络请求以字节范围XXXX-*发出,其中XXXX应为缓冲区大小)

    这解决了这个问题的原因是,通过缓冲所有这些数据,aviocontext不再需要发出新的网络请求来获取音频数据。音频数据已缓冲(或至少第一个位置已缓冲)

    可能有更好的方法来解决这个问题,似乎apple MOV文件出于某种原因将视频和音频数据与这些海量数据块分开,这导致ffmpeg为每一帧发出一百万个网络请求。

    我找到了一个解决方法(大约):

    将AVFormatContext的io_open回调设置为您自己的函数,然后在调用该函数时,在调用默认io_open后,更改缓冲区大小

    static int (*IO_OPEN_DEFAULT)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options);
    
    int IO_OPEN_OVERRIDE(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options) {
        int result = IO_OPEN_DEFAULT(s, pb, url, flags, options);
        pb[0]->buffer_size = 41239179;
        return result;
    }
    
    这解决了问题。您将其设置为的值通常非常大(20到40MB)。打开格式上下文时,您可以从第二个网络请求字节范围中获取该值(第一个网络请求以字节范围0-*发出,然后第二个网络请求以字节范围XXXX-*发出,其中XXXX应为缓冲区大小)

    这解决了这个问题的原因是,通过缓冲所有这些数据,aviocontext不再需要发出新的网络请求来获取音频数据。音频数据已缓冲(或至少第一个位置已缓冲)

    也许有更好的方法来解决这个问题,似乎apple MOV文件出于某种原因将它们的视频和音频数据与这些大块分开,这导致ffmpeg为每一帧发出一百万个网络请求

    Metadata:
        major_brand     : qt  
        minor_version   : 0
        compatible_brands: qt  
        creation_time   : 2019-04-14T08:17:03.000000Z
        com.apple.quicktime.make: Apple
        com.apple.quicktime.model: iPhone 7
        com.apple.quicktime.software: 12.2
        com.apple.quicktime.creationdate: 2019-04-14T11:17:03+0300
      Duration: 00:00:16.83, bitrate: N/A
        Stream #0:0(und), 0, 1/600: Video: h264, 1 reference frame (avc1 / 0x31637661), none(bt709), 1920x1080 (0x0), 0/1, 15301 kb/s, 30 fps, 30 tbr, 600 tbn (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Video
          encoder         : H.264
        Stream #0:1(und), 0, 1/44100: Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, 100 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Audio
        Stream #0:2(und), 0, 1/600: Data: none (mebx / 0x7862656D), 0/1, 0 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Metadata
        Stream #0:3(und), 0, 1/600: Data: none (mebx / 0x7862656D), 0/1, 0 kb/s (default)
        Metadata:
          creation_time   : 2019-04-14T08:17:03.000000Z
          handler_name    : Core Media Metadata
    
    static int (*IO_OPEN_DEFAULT)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options);
    
    int IO_OPEN_OVERRIDE(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options) {
        int result = IO_OPEN_DEFAULT(s, pb, url, flags, options);
        pb[0]->buffer_size = 41239179;
        return result;
    }