Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffmpeg software decoder implementation #461

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Full documentation for rocDecode is available at [https://rocm.docs.amd.com/proj
* Clang is now the default CXX compiler.
* The new minimum supported version of va-api is 1.16.
* New build and runtime options have been added to the `rocDecode-setup.py` setup script.
* Added FFMpeg based software decoding into utils.
* Modified videodecode sample to allow FFMpeg based decoding
AryanSalmanpour marked this conversation as resolved.
Show resolved Hide resolved

### Removed

Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ if(HIP_FOUND AND Libva_FOUND)
# install rocDecode samples -- {ROCM_PATH}/share/rocdecode
install(DIRECTORY cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME} COMPONENT dev)
install(DIRECTORY utils/rocvideodecode DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
install(DIRECTORY utils/ffmpegvideodecode DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
install(FILES samples/videoDecode/CMakeLists.txt samples/videoDecode/README.md samples/videoDecode/videodecode.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/videoDecode COMPONENT dev)
install(FILES samples/videoDecodeMem/CMakeLists.txt samples/videoDecodeMem/README.md samples/videoDecodeMem/videodecodemem.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/videoDecodeMem COMPONENT dev)
install(FILES samples/videoDecodePerf/CMakeLists.txt samples/videoDecodePerf/README.md samples/videoDecodePerf/videodecodeperf.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/videoDecodePerf COMPONENT dev)
Expand Down
3 changes: 3 additions & 0 deletions api/rocdecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ typedef enum rocDecVideoSurfaceFormat_enum {
rocDecVideoSurfaceFormat_YUV444 = 2, /**< Planar YUV [Y plane followed by U and V planes] */
rocDecVideoSurfaceFormat_YUV444_16Bit = 3, /**< 16 bit Planar YUV [Y plane followed by U and V planes].
Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */
rocDecVideoSurfaceFormat_YUV420 = 4, /**< Planar YUV [Y plane followed by U and V planes in 4:2:0 format] */
rocDecVideoSurfaceFormat_YUV420_16Bit = 5, /**< 16 bit Planar YUV [Y plane followed by U and V planes in ].
Can be used for 10 bit(LSB), 12 bit (LSB) */
} rocDecVideoSurfaceFormat;

/**************************************************************************************************************/
Expand Down
4 changes: 2 additions & 2 deletions samples/videoDecode/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ if(HIP_FOUND AND FFMPEG_FOUND AND ROCDECODE_FOUND)
${AVFORMAT_INCLUDE_DIR})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${FFMPEG_LIBRARIES})
# rocDecode and utils
include_directories (${ROCDECODE_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../../utils ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode)
include_directories (${ROCDECODE_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../../utils ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/ffmpegvideodecode)
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${ROCDECODE_LIBRARY})
# sample app exe
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp)
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/ffmpegvideodecode/ffmpeg_video_dec.cpp)
add_executable(${PROJECT_NAME} ${SOURCES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
Expand Down
51 changes: 37 additions & 14 deletions samples/videoDecode/videodecode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ THE SOFTWARE.
#endif
#include "video_demuxer.h"
#include "roc_video_dec.h"
#include "ffmpeg_video_dec.h"
#include "common.h"

void ShowHelpAndExit(const char *option = NULL) {
std::cout << "Options:" << std::endl
<< "-i Input File Path - required" << std::endl
<< "-o Output File Path - dumps output if requested; optional" << std::endl
<< "-d GPU device ID (0 for the first device, 1 for the second, etc.); optional; default: 0" << std::endl
<< "-backend backend (0 for GPU, 1 CPU-FFMpeg, 2 CPU-FFMpeg No threading); optional; default: 0" << std::endl
<< "-f Number of decoded frames - specify the number of pictures to be decoded; optional" << std::endl
<< "-z force_zero_latency (force_zero_latency, Decoded frames will be flushed out for display immediately); optional;" << std::endl
<< "-disp_delay -specify the number of frames to be delayed for display; optional; default: 1" << std::endl
Expand All @@ -68,6 +70,7 @@ int main(int argc, char **argv) {
int dump_output_frames = 0;
int device_id = 0;
int disp_delay = 1;
int backend = 0;
bool b_force_zero_latency = false; // false by default: enabling this option might affect decoding performance
bool b_extract_sei_messages = false;
bool b_generate_md5 = false;
Expand Down Expand Up @@ -106,6 +109,14 @@ int main(int argc, char **argv) {
dump_output_frames = 1;
continue;
}
if (!strcmp(argv[i], "-backend")) {
if (++i == argc) {
ShowHelpAndExit("-backend");
}
backend = atoi(argv[i]);
continue;
}

if (!strcmp(argv[i], "-d")) {
if (++i == argc) {
ShowHelpAndExit("-d");
Expand Down Expand Up @@ -203,18 +214,30 @@ int main(int argc, char **argv) {
try {
std::size_t found_file = input_file_path.find_last_of('/');
std::cout << "info: Input file: " << input_file_path.substr(found_file + 1) << std::endl;
RocVideoDecoder *viddec;
rrawther marked this conversation as resolved.
Show resolved Hide resolved
VideoDemuxer demuxer(input_file_path.c_str());
VideoSeekContext video_seek_ctx;
rocDecVideoCodec rocdec_codec_id = AVCodec2RocDecVideoCodec(demuxer.GetCodecID());
RocVideoDecoder viddec(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
if(!viddec.CodecSupported(device_id, rocdec_codec_id, demuxer.GetBitDepth())) {
std::cerr << "GPU doesn't support codec!" << std::endl;
if (!backend) // gpu backend
viddec = new RocVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
else {
std::cout << "info: RocDecode is using CPU backend!" << std::endl;
bool use_threading = false;
if (mem_type == OUT_SURFACE_MEM_DEV_INTERNAL) mem_type = OUT_SURFACE_MEM_DEV_COPIED; // mem_type internal is not supported in this mode
if (backend == 1) {
viddec = new FFMpegVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
} else
viddec = new FFMpegVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay, true);
}

if(!viddec->CodecSupported(device_id, rocdec_codec_id, demuxer.GetBitDepth())) {
std::cerr << "rocDecode doesn't support codec!" << std::endl;
return 0;
}
std::string device_name, gcn_arch_name;
int pci_bus_id, pci_domain_id, pci_device_id;

viddec.GetDeviceinfo(device_name, gcn_arch_name, pci_bus_id, pci_domain_id, pci_device_id);
viddec->GetDeviceinfo(device_name, gcn_arch_name, pci_bus_id, pci_domain_id, pci_device_id);
std::cout << "info: Using GPU device " << device_id << " - " << device_name << "[" << gcn_arch_name << "] on PCI bus " <<
std::setfill('0') << std::setw(2) << std::right << std::hex << pci_bus_id << ":" << std::setfill('0') << std::setw(2) <<
std::right << std::hex << pci_domain_id << "." << pci_device_id << std::dec << std::endl;
Expand Down Expand Up @@ -244,9 +267,9 @@ int main(int argc, char **argv) {
reconfig_params.p_reconfig_user_struct = &reconfig_user_struct;

if (b_generate_md5) {
viddec.InitMd5();
viddec->InitMd5();
}
viddec.SetReconfigParams(&reconfig_params);
viddec->SetReconfigParams(&reconfig_params);

do {
auto start_time = std::chrono::high_resolution_clock::now();
Expand Down Expand Up @@ -275,22 +298,22 @@ int main(int argc, char **argv) {
if (n_video_bytes == 0) {
pkg_flags |= ROCDEC_PKT_ENDOFSTREAM;
}
n_frame_returned = viddec.DecodeFrame(pvideo, n_video_bytes, pkg_flags, pts, &decoded_pics);
n_frame_returned = viddec->DecodeFrame(pvideo, n_video_bytes, pkg_flags, pts, &decoded_pics);

if (!n_frame && !viddec.GetOutputSurfaceInfo(&surf_info)) {
if (!n_frame && !viddec->GetOutputSurfaceInfo(&surf_info)) {
std::cerr << "Error: Failed to get Output Surface Info!" << std::endl;
break;
}
for (int i = 0; i < n_frame_returned; i++) {
pframe = viddec.GetFrame(&pts);
pframe = viddec->GetFrame(&pts);
if (b_generate_md5) {
viddec.UpdateMd5ForFrame(pframe, surf_info);
viddec->UpdateMd5ForFrame(pframe, surf_info);
}
if (dump_output_frames && mem_type != OUT_SURFACE_MEM_NOT_MAPPED) {
viddec.SaveFrameToFile(output_file_path, pframe, surf_info);
viddec->SaveFrameToFile(output_file_path, pframe, surf_info);
}
// release frame
viddec.ReleaseFrame(pts);
viddec->ReleaseFrame(pts);
}
auto end_time = std::chrono::high_resolution_clock::now();
auto time_per_decode = std::chrono::duration<double, std::milli>(end_time - start_time).count();
Expand All @@ -303,7 +326,7 @@ int main(int argc, char **argv) {

} while (n_video_bytes);

n_frame += viddec.GetNumOfFlushedFrames();
n_frame += viddec->GetNumOfFlushedFrames();
std::cout << "info: Total pictures decoded: " << n_pic_decoded << std::endl;
std::cout << "info: Total frames output/displayed: " << n_frame << std::endl;
if (!dump_output_frames) {
Expand All @@ -320,7 +343,7 @@ int main(int argc, char **argv) {
}
if (b_generate_md5) {
uint8_t *digest;
viddec.FinalizeMd5(&digest);
viddec->FinalizeMd5(&digest);
std::cout << "MD5 message digest: ";
for (int i = 0; i < 16; i++) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(digest[i]);
Expand Down
Loading