Skip to content

Commit

Permalink
Merge pull request #4 from izwb003/build_mxlplayer
Browse files Browse the repository at this point in the history
Completed mxlplayer.
  • Loading branch information
izwb003 authored Mar 28, 2024
2 parents 07bf9c4 + 83adfb8 commit a98ec7c
Show file tree
Hide file tree
Showing 37 changed files with 2,540 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "external/SDL"]
path = external/SDL
url = https://github.com/libsdl-org/SDL
55 changes: 39 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.18)

project(AVPStudio VERSION 0.2.0 LANGUAGES CXX)

# Link ffmpeg
if(WIN32)
set(FFMPEG_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg)
set(FFMPEG_VERSION 6.1.1)

# Download ffmpeg gyan.dev builds from GitHub
if(NOT EXISTS ${FFMPEG_PATH})
file(DOWNLOAD
https://github.com/GyanD/codexffmpeg/releases/download/${FFMPEG_VERSION}/ffmpeg-${FFMPEG_VERSION}-full_build-shared.zip
${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg.zip
SHOW_PROGRESS
)
file(ARCHIVE_EXTRACT
INPUT ${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg.zip
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/external
)
file(RENAME
${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg-${FFMPEG_VERSION}-full_build-shared
${FFMPEG_PATH}
)
file(REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg.zip)
endif()
endif(WIN32)

find_library(LIBAVUTIL_PATH avutil ${FFMPEG_PATH}/lib)
find_library(LIBAVCODEC_PATH avcodec ${FFMPEG_PATH}/lib)
find_library(LIBAVFORMAT_PATH avformat ${FFMPEG_PATH}/lib)
find_library(LIBAVFILTER_PATH avfilter ${FFMPEG_PATH}/lib)
find_library(LIBSWSCALE_PATH swscale ${FFMPEG_PATH}/lib)
find_library(LIBSWRESAMPLE_PATH swresample ${FFMPEG_PATH}/lib)

include_directories(${FFMPEG_PATH}/include)

# Link SDL
add_subdirectory(external/SDL)
include_directories(external/SDL/include)

# Necessary Qt settings
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
Expand Down Expand Up @@ -82,20 +119,6 @@ set_target_properties(AVPStudio PROPERTIES
# GNU include
include(GNUInstallDirs)

# Link ffmpeg
if(WIN32)
set(FFMPEG_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/ffmpeg)
endif(WIN32)

find_library(LIBAVUTIL_PATH avutil ${FFMPEG_PATH}/lib)
find_library(LIBAVCODEC_PATH avcodec ${FFMPEG_PATH}/lib)
find_library(LIBAVFORMAT_PATH avformat ${FFMPEG_PATH}/lib)
find_library(LIBAVFILTER_PATH avfilter ${FFMPEG_PATH}/lib)
find_library(LIBSWSCALE_PATH swscale ${FFMPEG_PATH}/lib)
find_library(LIBSWRESAMPLE_PATH swresample ${FFMPEG_PATH}/lib)

include_directories(${FFMPEG_PATH}/include)

# Link libraries
target_link_libraries(AVPStudio PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
Expand All @@ -113,7 +136,7 @@ target_link_libraries(AVPStudio PRIVATE
add_subdirectory(tools)

# Set install rules
install(TARGETS AVPStudio wavgenerator
install(TARGETS AVPStudio wavgenerator imageorganizer mxlplayer
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
Expand Down
43 changes: 33 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ AVPStudio是一个编码工具。它可以将任意视频按照该预设的分
### 素材准备
杜比影院动态视听走廊具有三种不同的规格。三种规格的具体参数如下:

|规格|尺寸|分辨率|音频轨道|
|---|---|---|---|
|Small|5.5m x 2.1m|2830W x 1080H|7.1 PCM Surround|
|Medium|9m x 2.1m|4633W x 1080H|7.1 PCM Surround|
|Large|12m x 2.1m|6167W x 1080H|7.1 PCM Surround|
| 规格 | 尺寸 | 分辨率 | 音频轨道 |
| ------ | ----------- | ------------- | ---------------- |
| Small | 5.5m x 2.1m | 2830W x 1080H | 7.1 PCM Surround |
| Medium | 9m x 2.1m | 4633W x 1080H | 7.1 PCM Surround |
| Large | 12m x 2.1m | 6167W x 1080H | 7.1 PCM Surround |

有关目标影院的具体规格,可向影院工作人员咨询。若对方无法透露准确信息,可自行对实际投影区域进行测量。

Expand Down Expand Up @@ -47,17 +47,32 @@ AVPStudio是一个编码工具。它可以将任意视频按照该预设的分

这样,通过将“![](images/pandorasbox_cue_mark.png)”拉至更远的位置(甚至视频末尾),即可让循环(cue)持续时间更长以避免中途返回开头。

## 附加工具

### AVPStudio ImageOrganizer
用于将图片构建为符合杜比影院动态视听走廊分离画面的图片工具。

若您的放映内容仅为单张静态图片,该工具可以省去制作视频的工作。

### AVPStudio WAVGenerator
用于生成音频WAV的工具。

可搭配ImageOrganizer用于为图片放映内容添加背景音乐,亦可用于及时调整WAV音频的音量大小。

### AVPStudio MXLPlayer
MXL播放器。

可播放转换完成的(或者官方的)mxl文件预览实际放映效果,亦可将mxl文件转换为H264 MP4视频。

## 技术信息

### 原理说明
有关实现的具体原理及画面结构,请参阅[此专栏](https://www.bilibili.com/read/cv27334455/)

### 构建说明
截至目前,软件仅在Windows环境下调试并测试通过,尚未针对Linux及macOS环境进行配置。

Windows环境下,请您在开始构建前提前编译ffmpeg库,或在[gyan.dev](https://www.gyan.dev/ffmpeg/builds/)等地下载预构建好的版本。
截至目前,软件仅在Windows环境下调试并测试通过,尚未针对Linux及macOS环境进行配置与调试。

在项目中新建```external/ffmpeg```文件夹,并将构建好的ffmpeg库拷贝到该文件夹中。确保其链接库(```.dll.a``````.lib```等)可以在```external/ffmpeg/lib```下被查找到
CMake脚本已被调整为默认从互联网下载预构建ffmpeg。请确保构建时互联网连接畅通。您也可以参阅CMakeLists.txt自行配置外部库

构建需要完整的Qt6环境。项目必须使用以下Qt库:Qt6Core, Qt6Widgets, Qt6Multimedia, Qt6MultimediaWidgets。

Expand Down Expand Up @@ -85,4 +100,12 @@ AVPStudio基于Qt许可证使用Qt6技术。

AVPStudio基于LGPLv2.1及GPLv2使用来自[FFmpeg](https://ffmpeg.org/)的软件。

AVPStudio是在[GNU GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC1)下开放源代码的软件。
AVPStudio MXLPlayer基于zlib license使用来自[SDL](https://www.libsdl.org/)的软件。

AVPStudio是在[GNU GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC1)下开放源代码的软件。

## 附表 中华人民共和国大陆地区Dolby Cinema部分参数表(2023年7月)

***网友制表,出处见水印。信息仅供参考。***

![](images/cn_dbyc_list_202307.jpg)
1 change: 1 addition & 0 deletions external/SDL
Submodule SDL added at 5df737
Binary file added images/cn_dbyc_list_202307.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/close.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/mute.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/volume.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions res/resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<file>images/play.png</file>
<file>images/completed.png</file>
<file>images/error.png</file>
<file>images/mute.png</file>
<file>images/volume.png</file>
<file>images/close.png</file>
</qresource>
<qresource prefix="/texts">
<file>texts/aboutinfo_zh_CN.md</file>
Expand Down
6 changes: 4 additions & 2 deletions res/texts/aboutinfo_zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### 编写者

[@izwb003](https://space.bilibili.com/36937211) [@筱理_Rize](https://space.bilibili.com/3848521)
[@izwb003](https://space.bilibili.com/36937211)

### 原理证明

Expand All @@ -16,7 +16,7 @@

### 同时提供支持

[@神奇的红毛丹](https://space.bilibili.com/364856318/) @一个复杂精密的好名字 @寒 @还有这种事? @茶. @R.M.Dolby @Schon @WuChangXD @妙木山蛤蟆仙人
[@神奇的红毛丹](https://space.bilibili.com/364856318/) [@多真燐](https://space.bilibili.com/8275564) @一个复杂精密的好名字 @寒 @还有这种事? @茶. @R.M.Dolby @Schon @WuChangXD @妙木山蛤蟆仙人

(以上排名不分先后)

Expand All @@ -41,6 +41,8 @@ AVPStudio基于Qt许可证使用Qt6技术。

AVPStudio基于LGPLv2.1及GPLv2使用来自[FFmpeg](https://ffmpeg.org/)的软件。它的源代码可以在[GitHub](https://github.com/izwb003/AVPStudio)下载。

AVPStudio MXLPlayer基于zlib license使用来自[SDL](https://www.libsdl.org/)的软件。

### 开放源代码许可

```
Expand Down
78 changes: 65 additions & 13 deletions src/doprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/* To anyone who reads my code:
* I am not very familiar with multi-thread programming.
* I was sleeping when my teacher taught me these things.
* So I may have made some foolish mistakes in this regard, such as using terminate() extensively.
* If I have the opportunity to continue maintaining these codes in the future, perhaps I can use more enriched experience to correct them.
* But now, they are "usable" - limited to being "able to run", that's all.
*/

#include "doprocess.h"

#include "settings.h"
Expand All @@ -41,23 +50,26 @@ static const char *filterGraphLarge =
"[scaled]split[scaled1][scaled2];"
"[scaled1]crop=3840:1080:0:0[left];"
"[scaled2]crop=3840:1080:2327:0[right];"
"[left][right]vstack=2[out]";
"[left][right]vstack=2[ready];"
"[ready]fps=24[out]";
static const char *filterGraphMedium =
"[in]pad=iw:ih:0:0:black[expanded];"
"[expanded]scale=4632:1080[scaled];"
"[scaled]pad=6166:1080:767:0:black[padded];"
"[padded]split[padded1][padded2];"
"[padded1]crop=3840:1080:0:0[left];"
"[padded2]crop=3840:1080:2327:0[right];"
"[left][right]vstack=2[out]";
"[left][right]vstack=2[ready];"
"[ready]fps=24[out]";
static const char *filterGraphSmall =
"[in]pad=iw:ih:0:0:black[expanded];"
"[expanded]scale=2830:1080[scaled];"
"[scaled]pad=6166:1080:1668:0:black[padded];"
"[padded]split[padded1][padded2];"
"[padded1]crop=3840:1080:0:0[left];"
"[padded2]crop=3840:1080:2327:0[right];"
"[left][right]vstack=2[out]";
"[left][right]vstack=2[ready];"
"[ready]fps=24[out]";

template<typename T> int toUpperInt(T val)
{
Expand Down Expand Up @@ -112,6 +124,7 @@ void TDoProcess::run()
AVFilterInOut *videoFilterOutput = NULL;

AVFilterContext *videoFilterPadCxt = NULL;
AVFilterContext *videoFilterFpsCxt = NULL;

const AVFilter *videoFilterSrc = NULL;
AVFilterContext *videoFilterSrcCxt = NULL;
Expand All @@ -136,6 +149,8 @@ void TDoProcess::run()

SwrContext *resamplerCxt = NULL;

uint64_t audioPTSCounter = 0;

// Open input file and find stream info
iVideoFmtCxt = avformat_alloc_context();
avError = avformat_open_input(&iVideoFmtCxt, settings.inputVideoPath.toUtf8(), 0, 0);
Expand All @@ -153,7 +168,7 @@ void TDoProcess::run()

// Get input video and audio stream
iVideoStreamID = av_find_best_stream(iVideoFmtCxt, AVMEDIA_TYPE_VIDEO, -1, -1, &iVideoDecoder, 0);
if(avError < 0)
if(iVideoStreamID == AVERROR_STREAM_NOT_FOUND)
{
avErrorMsg = tr("加载输入文件失败:找不到视频流。");
goto end;
Expand Down Expand Up @@ -209,6 +224,7 @@ void TDoProcess::run()
oVideoEncoderCxt -> color_trc = settings.outputColor.outputVideoColorTrac;
oVideoEncoderCxt -> profile = 0;
oVideoEncoderCxt -> max_b_frames = 0;
oVideoEncoderCxt -> framerate = settings.outputFrameRate;

if(iAudioStreamID != AVERROR_STREAM_NOT_FOUND)
{
Expand All @@ -235,7 +251,7 @@ void TDoProcess::run()
goto end;
}
oVideoStream -> time_base = oVideoEncoderCxt->time_base;
oVideoStream ->r_frame_rate = settings.outputFrameRate;
oVideoStream -> r_frame_rate = settings.outputFrameRate;

if(iAudioStreamID != AVERROR_STREAM_NOT_FOUND)
{
Expand Down Expand Up @@ -403,6 +419,12 @@ void TDoProcess::run()
}
}

if(settings.size == AVP::kAVPMediumSize || settings.size == AVP::kAVPMediumSize)
videoFilterFpsCxt = avfilter_graph_get_filter(videoFilterGraph, "Parsed_fps_7");
if(settings.size == AVP::kAVPLargeSize)
videoFilterFpsCxt = avfilter_graph_get_filter(videoFilterGraph, "Parsed_fps_6");
avError = av_opt_set(videoFilterFpsCxt, "fps", QString::number(settings.outputFrameRate.num).toUtf8() + "/" + QString::number(settings.outputFrameRate.den).toUtf8(), AV_OPT_SEARCH_CHILDREN);

avError = avfilter_graph_config(videoFilterGraph, 0);
if(avError < 0)
{
Expand All @@ -428,17 +450,29 @@ void TDoProcess::run()

// Apply filter
avError = av_buffersrc_add_frame(videoFilterSrcCxt, vFrameIn);
avError = av_buffersink_get_frame(videoFilterSinkCxt, vFrameFiltered);
while(true)
{
avError = av_buffersink_get_frame(videoFilterSinkCxt, vFrameFiltered);
if(avError == AVERROR(EAGAIN) || avError == AVERROR_EOF)
break;

// Rescale to YUV422
avError = sws_scale_frame(scale422Cxt, vFrameOut, vFrameFiltered);
// Rescale to YUV422
avError = sws_scale_frame(scale422Cxt, vFrameOut, vFrameFiltered);

// Encode
avError = avcodec_send_frame(oVideoEncoderCxt, vFrameOut);
avError = avcodec_receive_packet(oVideoEncoderCxt, packet);
av_packet_rescale_ts(packet, oVideoEncoderCxt->time_base, oVideoFmtCxt->streams[0]->time_base);
avError = av_write_frame(oVideoFmtCxt, packet);
// Encode
avError = avcodec_send_frame(oVideoEncoderCxt, vFrameOut);
avError = avcodec_receive_packet(oVideoEncoderCxt, packet);
av_packet_rescale_ts(packet, oVideoEncoderCxt->time_base, oVideoFmtCxt->streams[0]->time_base);
avError = av_interleaved_write_frame(oVideoFmtCxt, packet);

// Unref frame
av_frame_unref(vFrameIn);
av_frame_unref(vFrameFiltered);
av_frame_unref(vFrameOut);
}
}
// Unref packet
av_packet_unref(packet);
}
}

Expand Down Expand Up @@ -517,11 +551,21 @@ void TDoProcess::run()
avError = swr_config_frame(resamplerCxt, aFrameOut, aFrameFiltered);
avError = swr_convert_frame(resamplerCxt, aFrameOut, aFrameFiltered);

aFrameOut -> pts = audioPTSCounter;
audioPTSCounter += oAudioEncoderCxt->frame_size;

// Encode
avError = avcodec_send_frame(oAudioEncoderCxt, aFrameOut);
avError = avcodec_receive_packet(oAudioEncoderCxt, packet);
avError = av_write_frame(oAudioFmtCxt, packet);

// Unref frames
av_frame_unref(aFrameIn);
av_frame_unref(aFrameFiltered);
av_frame_unref(aFrameOut);
}
// Unref packet
av_packet_unref(packet);
}
}
}
Expand Down Expand Up @@ -572,6 +616,11 @@ void TDoProcess::run()
av_frame_free(&vFrameFiltered);
av_frame_free(&vFrameOut);

avfilter_free(videoFilterSrcCxt);
avfilter_free(videoFilterSinkCxt);
avfilter_free(videoFilterPadCxt);
avfilter_free(videoFilterFpsCxt);

avfilter_graph_free(&videoFilterGraph);
avfilter_inout_free(&videoFilterInput);
avfilter_inout_free(&videoFilterOutput);
Expand All @@ -582,6 +631,9 @@ void TDoProcess::run()
av_frame_free(&aFrameFiltered);
av_frame_free(&aFrameOut);

avfilter_free(volumeFilterSrcCxt);
avfilter_free(volumeFilterSinkCxt);
avfilter_free(volumeFilterCxt);
avfilter_graph_free(&volumeFilterGraph);

swr_free(&resamplerCxt);
Expand Down
Loading

0 comments on commit a98ec7c

Please sign in to comment.