在Java JVM中处理图像(更不用说视频)一直是一项艰巨的任务。 自JDK7以来, ImageIO类已经走了很长一段路,再加上常见的SDK错误,并不总是能给您您所期望的(图像质量差,不总是支持所有类型的JPEG标准,…)。 在这行的最后,最好使用专门为图像处理编写的开源库,例如ImageMagick和GraphicsMagick。 这些库也是我们在ImageServer跨模块中使用的库,用于为图像,PDF等生成缩略图和变体。
最近,我们参与了一个项目,在该项目中,我们不得不显示和播放客户上传的音频/视频文件。 该页面还显示了媒体资产中的一些元数据,文件在上传后将被拒绝(例如,如果比特率或其他元数据不足)。 简而言之,我们必须解析各种音频和视频资产的元数据,然后将此媒体文件呈现给客户。 我们这里不是在谈论Netflix流媒体平台,而是一些基本的音频/视频流媒体。
我们寻找的库可以解析视频文件(在本例中,我们正在谈论MXF文件)以提取元数据。 有类似Netflix Photon( https://github.com/Netflix/photon/releases )和https://github.com/jforaci/mxf-reader的库 。 但是,您真的要在JVM中解析和读取文件吗? 简短的答案是“不”,您不希望所有这些东西都进入Java内存。
那有什么选择呢?
元数据解析
为此,我们研究了ffmpeg和MediaInfo。
如果您曾经将自己的(S)VCD,DVD磁盘转换为MKV(Matroska容器)或AVI,MPEG格式,那么您肯定会注意到ffmpeg是用于转换/解析媒体文件的事实上的工具。
MediaInfo是客户建议的工具,可从媒体文件提供结构化的元数据探测。
我们编写的解析器支持ffmpeg和Mediainfo的灵活性,并将这些工具中的JSON映射到相同的数据结构。 两者给出相似的输出
ffmpeg探针
$ ffprobe -show_format -show_streams audiocheck.net_polarity_guitarOK.wav -print_format json -loglevel 0
{"streams": [{"index": 0,"codec_name": "pcm_s16le","codec_long_name": "PCM signed 16-bit little-endian","codec_type": "audio","codec_time_base": "1/44100","codec_tag_string": "[1][0][0][0]","codec_tag": "0x0001","sample_fmt": "s16","sample_rate": "44100","channels": 2,"bits_per_sample": 16,"r_frame_rate": "0/0","avg_frame_rate": "0/0","time_base": "1/44100","duration_ts": 224041,"duration": "5.080295","bit_rate": "1411200","disposition": {"default": 0,"dub": 0,"original": 0,"comment": 0,"lyrics": 0,"karaoke": 0,"forced": 0,"hearing_impaired": 0,"visual_impaired": 0,"clean_effects": 0,"attached_pic": 0,"timed_thumbnails": 0}}],"format": {"filename": "audiocheck.net_polarity_guitarOK.wav","nb_streams": 1,"nb_programs": 0,"format_name": "wav","format_long_name": "WAV / WAVE (Waveform Audio)","duration": "5.080295","size": "896208","bit_rate": "1411269","probe_score": 99}
}
$ mediainfo --output=JSON audiocheck.net_polarity_guitarOK.wav
{
"media": {
"@ref": "audiocheck.net_polarity_guitarOK.wav",
"track": [
{
"@type": "General",
"AudioCount": "1",
"FileExtension": "wav",
"Format": "Wave",
"FileSize": "896208",
"Duration": "5.080",
"OverallBitRate_Mode": "CBR",
"OverallBitRate": "1411351",
"StreamSize": "44",
"File_Modified_Date": "UTC 2020-03-03 12:02:30",
"File_Modified_Date_Local": "2020-03-03 13:02:30"
},
{
"@type": "Audio",
"Format": "PCM",
"Format_Settings_Endianness": "Little",
"Format_Settings_Sign": "Signed",
"CodecID": "1",
"Duration": "5.080",
"BitRate_Mode": "CBR",
"BitRate": "1411200",
"Channels": "2",
"SamplingRate": "44100",
"SamplingCount": "224028",
"BitDepth": "16",
"StreamSize": "896164",
"StreamSize_Proportion": "0.99995"
}
]
}
}
请注意,如果您使用的是Debian常规安装,则需要从https://mediaarea.net/zh-CN/MediaInfo/Download/Debian安装.deb软件包–否则,您将被(非常)旧版本所困扰,该版本具有没有JSON输出。
将这些输出包装到一个通用的数据结构中足以完成我们的元数据处理检查并存储一些元数据以用于显示(例如,媒体文件的持续时间和格式)。
缩图产生
对于缩略图的生成,有两个要求。 音频文件必须生成波形。 视频文件必须为该视频生成良好的缩略图。
根据上面的元数据,您可以快速区分上传的媒体文件是音频文件还是视频文件(视频文件具有视频流/轨道)。
两者都遵循另一条缩略图生成轨道。
音频缩略图生成和音频播放
要在概览页面上显示波形,我们只需使用ffmpeg使用以下命令生成波形
$ ffmpeg -y -i inputfile -filter_complex "showwavespic=colors=#007bff:split_channels=1" -frames:v 1 -c:v png -loglevel -8
这将生成PNG格式的波形,并拆分波形中的不同音频通道。 生成此图像后,我们将其上传到我们的Across ImageServer。
在音频资产的详细信息页面上,我们使用WaveSurfer( https://wavesurfer-js.org/ )播放音频文件并渲染音频通道-那里没什么特别的。
视频缩略图生成和视频播放
要在概述页面上显示缩略图,我们可以使用ffmpeg缩略图过滤器
$ ffmpeg -i inputFile -vf "thumbnail" -frames:v 1
该过滤器非常适合于对优质缩略图进行评价。 您可以做更多更有趣的事情,例如
$ ffmpeg -ss 3 -i inputFile -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.png
这将生成5个缩略图帧,从一开始就跳过3秒钟(可能是字幕),并抓取“场景变化”大于50%的帧。 为此,在https://superuser.com/questions/538112/含义ful-thumbnails- for-a-video-using- ffmpeg进行了很好的讨论。
最终,客户认为最后一个第二帧将是最适合他们的目的的,因为该帧通常包含商业视频的闭包。
由于视频为25fps,我们最终得到的命令如下(其中89是帧总数– 26 )。 是的,26…因为ffmpeg对帧进行从零开始的计数。
$ ffmpeg -i inputFile -vf "select=gte(n\,89)" -frames:v 1
然后将生成的缩略图上传到ImageServer中,仅此而已。 现在...播放视频文件...
嗯,网络上的视频播放器不支持MXF文件,最好的选择是将该视频容器格式转码为MP4(这是当今最兼容的跨浏览器格式)。
幸运的是,ffmpeg可以解救,尽管要找到合适的命令来生成可在大多数浏览器中播放的MP4的命令可能具有挑战性。
$ ffmpeg -y -i inputFile -vcodec libx264 -pix_fmt yuv420p -profile:v baseline -level 3 transcodedFile
此命令生成具有基线配置文件和YUV420P颜色编码方案的MP4文件。 此基准配置文件和配色方案可确保在Safari(适用于Mac)上正确显示。
使用Across FileRepositoryModule将转码后的文件存储在后备存储(在这种情况下为Azure BLOB存储,但它也支持AWS S3或本地存储)。
现在...真正播放视频文件...
我们需要网络上的视频播放器来实现这一目标。 最常见的库是videojs( https://videojs.com/ ),该库易于设置且可自定义,足以满足我们的目的。
仅向<video>标签提供正确的url即可在Firefox和Chrome中立即产生结果,但是Safari顽固地播放该文件。
Safari尝试通过将范围标头添加到HTTP请求中,从而与其他苹果产品一样变得与众不同。 这是为了避免一次通过网络发送视频文件中的所有字节。
取而代之的是HTTP Range标头指定需要获取的字节范围。
使用Spring Boot中的ResourceRegion构造可以轻松完成此操作,以下博客对此有所帮助: https : //melgenek.github.io/spring-video-service
最后,安装程序能够:
- 从任何媒体文件中提取元数据
- 生成媒体文件的缩略图(音频波形和视频缩略图)
- 通过Wavesurfer播放音频文件
- 通过VideoJS播放视频文件
翻译自: https://www.javacodegeeks.com/2020/04/how-to-process-images-and-videos-within-java-jvm.html