sonysuqin / WasmVideoPlayer

Play file/stream with wasm & webgl & web audio api, using ffmpeg for multi codec support, especially for h265,support http, websocket, http-flv stream.
GNU General Public License v3.0
1.3k stars 375 forks source link

很多h265视频无法播放是怎么回事? #35

Closed yyqangular1 closed 4 years ago

yyqangular1 commented 5 years ago

之前发现hev1的h265视频无法播放,现在发现hvc1的h265视频也有无法播放的,这是什么情况?应该如何debug调查? 报错如下:

libffmpeg.js:1 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x647710] error reading header
[2019-11-4 14:28:35:73][Decoder][IF] openDecoder return 8
[2019-11-4 14:28:35:73][Player][IF] Open decoder response 8.
play error 8 status 0.

视频媒体信息如下:

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'h265.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf58.29.100
  Duration: 01:09:37.08, start: 0.000000, bitrate: 327 kb/s
    Stream #0:0(eng): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, progressive), 720x480 [SAR 32:27 DAR 16:9], 196 kb/s, 25 fps, 25 tbr, 12800 tbn, 25 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 125 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
sonysuqin commented 5 years ago

可以传一下不能播的文件吗?

yyqangular1 commented 5 years ago

@sonysuqin 我上传到百度网盘了。 链接: https://pan.baidu.com/s/1uYOVkEWJ8_GgfixsoSMU-w 提取码: bykj

yyqangular1 commented 5 years ago

另外,我还发现,貌似是文件很大后,就无法播放了,几分钟,有很多都可以播。十几分钟的可能就无法播放了。比如您demo中带的那个屌丝男士的7分多的视频,如果把两个拼接成一个15分钟的视频,就无法播放了。。我上传的那个视频就是您的原视频拼接的。 我本地实验了很多个视频,暂时发现临界点好像是12分钟,超过12分钟就播不了了,12分钟以内的目前不管是hev1还是hvc1都可以播放。

pzx601917159 commented 5 years ago

另外,我还发现,貌似是文件很大后,就无法播放了,几分钟,有很多都可以播。十几分钟的可能就无法播放了。比如您demo中带的那个屌丝男士的7分多的视频,如果把两个拼接成一个15分钟的视频,就无法播放了。。我上传的那个视频就是您的原视频拼接的。 我本地实验了很多个视频,暂时发现临界点好像是12分钟,超过12分钟就播不了了,12分钟以内的目前不管是hev1还是hvc1都可以播放。

是不是mp4文件,waitHeaderLength设置大一点,文件越大头越大

yyqangular1 commented 5 years ago

另外,我还发现,貌似是文件很大后,就无法播放了,几分钟,有很多都可以播。十几分钟的可能就无法播放了。比如您demo中带的那个屌丝男士的7分多的视频,如果把两个拼接成一个15分钟的视频,就无法播放了。。我上传的那个视频就是您的原视频拼接的。 我本地实验了很多个视频,暂时发现临界点好像是12分钟,超过12分钟就播不了了,12分钟以内的目前不管是hev1还是hvc1都可以播放。

是不是mp4文件,waitHeaderLength设置大一点,文件越大头越大

@pzx601917159 我也尝试过把waitHeaderLength放大2~10倍,但是还是一样的错误,看错误信息确实也是获取不到头信息。

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x644ba0] reached eof, corrupted STCO atom
libffmpeg.js:2012 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x644ba0] error reading header
sonysuqin commented 5 years ago

@pzx601917159 试了一下你传的文件,可以播,跟 @yyqangular1 说的一样,就是文件大了之后头也变大,改的地方是index.html里的: self.player.play(videoFileUrl, canvas, function (e) { console.log("play error " + e.error + " status " + e.status + "."); if (e.error == 1) { logger.logInfo("Finished."); } }, 1024000);

yyqangular1 commented 5 years ago

@pzx601917159 试了一下你传的文件,可以播,跟 @yyqangular1 说的一样,就是文件大了之后头也变大,改的地方是index.html里的: self.player.play(videoFileUrl, canvas, function (e) { console.log("play error " + e.error + " status " + e.status + "."); if (e.error == 1) { logger.logInfo("Finished."); } }, 1024000);

@sonysuqin 改大之后确实可以了,我这里的视频文件基本都是2个小时时长的,这个头的大小不好把控,1024000这个值在2个小时时长的视频也是无法播放的。只能放的更大。这个文件头最大能到多少我也没查到相关资料。

另外还有一个问题,比较大的视频,播放的时候,点击两次seek,浏览器直接出现崩溃了。

sonysuqin commented 5 years ago

文件越大头越大,加载时间越长,一般都是切成分段的,这样可以控制加载时间。

pzx601917159 commented 5 years ago

@yyqangular1 @sonysuqin
我之前也提了这个问题 https://github.com/sonysuqin/WasmVideoPlayer/issues/25 针对mp4文件我自己实现了一个方法解析mp4 header的长度,不知道有没有更好的方法,可以参考一下 主要做两点: 1.判断mp4 moov是不是在mdat之前,如果不是这个要加载的文件尾播放(这里要参考ffmpeg想方法兼容) 2.如果moov在mdat之前,mp4的header长度 ftyp+moov的长度 代码如下: unsigned int getU32(char* buf) { unsigned int ret; memcpy(&ret, buf, 4); return htonl(ret); } int getMp4HeaderSize() { int ret = 0; do { if (decoder == NULL || decoder->fp == NULL) { ret = -1; break; } fseek(decoder->fp, 0, SEEK_SET); int availableBytes = decoder->fileWritePos; if(availableBytes < 8) { break; } char buf[8]; int size = 0; int tag_type = 0; while(tag_type != MKTAG('m','o','o','v') && ret < availableBytes) { fseek(decoder->fp, ret, SEEK_SET); memset(buf, 0, sizeof(buf)); fread(buf, 8, 1, decoder->fp); size = getU32(buf); tag_type = MKTAG(buf[4],buf[5],buf[6],buf[7]); if(tag_type == MKTAG('m','d','a','t')) { ret = -1; break; } ret += size; } }while(0); return ret; }

yyqangular1 commented 5 years ago

@yyqangular1 @sonysuqin 我之前也提了这个问题

25

针对mp4文件我自己实现了一个方法解析mp4 header的长度,不知道有没有更好的方法,可以参考一下 主要做两点: 1.判断mp4 moov是不是在mdat之前,如果不是这个要加载的文件尾播放(这里要参考ffmpeg想方法兼容) 2.如果moov在mdat之前,mp4的header长度 ftyp+moov的长度 代码如下: unsigned int getU32(char* buf) { unsigned int ret; memcpy(&ret, buf, 4); return htonl(ret); } int getMp4HeaderSize() { int ret = 0; do { if (decoder == NULL || decoder->fp == NULL) { ret = -1; break; } fseek(decoder->fp, 0, SEEK_SET); int availableBytes = decoder->fileWritePos; if(availableBytes < 8) { break; } char buf[8]; int size = 0; int tag_type = 0; while(tag_type != MKTAG('m','o','o','v') && ret < availableBytes) { fseek(decoder->fp, ret, SEEK_SET); memset(buf, 0, sizeof(buf)); fread(buf, 8, 1, decoder->fp); size = getU32(buf); tag_type = MKTAG(buf[4],buf[5],buf[6],buf[7]); if(tag_type == MKTAG('m','d','a','t')) { ret = -1; break; } ret += size; } }while(0); return ret; }

我看了您写的这个判断方法,这个方法什么时候用呢?如果播放的时候先跑这个,那延迟的时间应该会更加长吧。

pzx601917159 commented 4 years ago

@yyqangular1 @sonysuqin 我之前也提了这个问题

25

针对mp4文件我自己实现了一个方法解析mp4 header的长度,不知道有没有更好的方法,可以参考一下 主要做两点: 1.判断mp4 moov是不是在mdat之前,如果不是这个要加载的文件尾播放(这里要参考ffmpeg想方法兼容) 2.如果moov在mdat之前,mp4的header长度 ftyp+moov的长度 代码如下: unsigned int getU32(char* buf) { unsigned int ret; memcpy(&ret, buf, 4); return htonl(ret); } int getMp4HeaderSize() { int ret = 0; do { if (decoder == NULL || decoder->fp == NULL) { ret = -1; break; } fseek(decoder->fp, 0, SEEK_SET); int availableBytes = decoder->fileWritePos; if(availableBytes < 8) { break; } char buf[8]; int size = 0; int tag_type = 0; while(tag_type != MKTAG('m','o','o','v') && ret < availableBytes) { fseek(decoder->fp, ret, SEEK_SET); memset(buf, 0, sizeof(buf)); fread(buf, 8, 1, decoder->fp); size = getU32(buf); tag_type = MKTAG(buf[4],buf[5],buf[6],buf[7]); if(tag_type == MKTAG('m','d','a','t')) { ret = -1; break; } ret += size; } }while(0); return ret; }

我看了您写的这个判断方法,这个方法什么时候用呢?如果播放的时候先跑这个,那延迟的时间应该会更加长吧。

我是想得到mp4的header大小,然后在js里面动态设置大小,因为设置太大了,首屏会很慢,设置太小了视频会无法播放。

yyqangular1 commented 4 years ago

@yyqangular1 @sonysuqin 我之前也提了这个问题

25

针对mp4文件我自己实现了一个方法解析mp4 header的长度,不知道有没有更好的方法,可以参考一下 主要做两点: 1.判断mp4 moov是不是在mdat之前,如果不是这个要加载的文件尾播放(这里要参考ffmpeg想方法兼容) 2.如果moov在mdat之前,mp4的header长度 ftyp+moov的长度 代码如下: unsigned int getU32(char* buf) { unsigned int ret; memcpy(&ret, buf, 4); return htonl(ret); } int getMp4HeaderSize() { int ret = 0; do { if (decoder == NULL || decoder->fp == NULL) { ret = -1; break; } fseek(decoder->fp, 0, SEEK_SET); int availableBytes = decoder->fileWritePos; if(availableBytes < 8) { break; } char buf[8]; int size = 0; int tag_type = 0; while(tag_type != MKTAG('m','o','o','v') && ret < availableBytes) { fseek(decoder->fp, ret, SEEK_SET); memset(buf, 0, sizeof(buf)); fread(buf, 8, 1, decoder->fp); size = getU32(buf); tag_type = MKTAG(buf[4],buf[5],buf[6],buf[7]); if(tag_type == MKTAG('m','d','a','t')) { ret = -1; break; } ret += size; } }while(0); return ret; }

我看了您写的这个判断方法,这个方法什么时候用呢?如果播放的时候先跑这个,那延迟的时间应该会更加长吧。

我是想得到mp4的header大小,然后在js里面动态设置大小,因为设置太大了,首屏会很慢,设置太小了视频会无法播放。

嗯,目前确实没有其他较好的解决办法。越大的视频目前遇到的问题也较多。 本问题票就先关闭了,感谢各位大佬。