From a1a3f65434e0097fcc598134cce033bf828c5701 Mon Sep 17 00:00:00 2001 From: Lina Sun Date: Sun, 29 Sep 2024 08:04:42 +0000 Subject: [PATCH 1/2] Remove dumping code related to macro MFX_DEBUG_DUMP_FRAME Will add dumping code in another way, input & output buffer dump for encoder & decoder will all be able to be configured by set property. Tracked-On: OAM-124732 Signed-off-by: Lina Sun --- c2_buffers/src/mfx_c2_frame_in.cpp | 6 -- .../include/mfx_c2_decoder_component.h | 6 -- .../src/mfx_c2_decoder_component.cpp | 69 ------------------- c2_utils/include/mfx_debug.h | 1 - 4 files changed, 82 deletions(-) diff --git a/c2_buffers/src/mfx_c2_frame_in.cpp b/c2_buffers/src/mfx_c2_frame_in.cpp index 8f80cd8e..9b150581 100755 --- a/c2_buffers/src/mfx_c2_frame_in.cpp +++ b/c2_buffers/src/mfx_c2_frame_in.cpp @@ -187,12 +187,6 @@ c2_status_t MfxC2FrameIn::MfxC2LoadSurfaceInSW(C2ConstGraphicBlock& c_graph_bloc } } -#if MFX_DEBUG_DUMP_FRAME == MFX_DEBUG_YES - static int frameIndex = 0; - static YUVWriter writer("/data/local/tmp",std::vector({}),"encoder_frame.log"); - writer.Write(m_yuvData.get(), stride, height, frameIndex++); -#endif - mfx_sts = InitMfxFrameSW(buf_pack.ordinal.timestamp.peeku(), buf_pack.ordinal.frameIndex.peeku(), m_yuvData.get(), m_yuvData.get()+y_plane_size, width, height, stride, MFX_FOURCC_NV12, m_mfxFrameInfo, m_pMfxFrameSurface); diff --git a/c2_components/include/mfx_c2_decoder_component.h b/c2_components/include/mfx_c2_decoder_component.h index f9d6fdbf..f9b26273 100755 --- a/c2_components/include/mfx_c2_decoder_component.h +++ b/c2_components/include/mfx_c2_decoder_component.h @@ -252,12 +252,6 @@ class MfxC2DecoderComponent : public MfxC2Component MFXVideoVPP* m_vpp; bool m_vppConversion = false; -#if MFX_DEBUG_DUMP_FRAME == MFX_DEBUG_YES - int m_count = 0; - std::mutex m_count_lock; - bool NeedDumpBuffer(); -#endif - /* -----------------------C2Parameters--------------------------- */ std::shared_ptr m_name; std::shared_ptr m_kind; diff --git a/c2_components/src/mfx_c2_decoder_component.cpp b/c2_components/src/mfx_c2_decoder_component.cpp index 11df780d..140846db 100755 --- a/c2_components/src/mfx_c2_decoder_component.cpp +++ b/c2_components/src/mfx_c2_decoder_component.cpp @@ -2266,42 +2266,6 @@ void MfxC2DecoderComponent::Drain(std::unique_ptr&& work) } } -#if MFX_DEBUG_DUMP_FRAME == MFX_DEBUG_YES -bool MfxC2DecoderComponent::NeedDumpBuffer() { - MFX_DEBUG_TRACE_FUNC; - const char* key = "mediacodec2.dump.buffer"; - char* value = new char[20]; - int len = property_get(key, value, "0"); - -#include -#include - - std::stringstream strValue; - strValue << value; - - unsigned int m_frame_number = 0; - strValue >> m_frame_number; - - m_count_lock.lock(); - if (m_count) { - delete[] value; - m_count_lock.unlock(); - return true; - } else { - delete[] value; - if (len > 0 && m_frame_number > 0) { - m_count = m_frame_number; - MFX_DEBUG_TRACE_PRINTF("--------triggered to dump %d buffers---------", m_frame_number); - property_set(key, "0"); - m_count_lock.unlock(); - return true; - } - m_count_lock.unlock(); - return false; - } -} -#endif - void MfxC2DecoderComponent::WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint sync_point) { MFX_DEBUG_TRACE_FUNC; @@ -2460,39 +2424,6 @@ void MfxC2DecoderComponent::WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint syn } m_updatingC2Configures.clear(); -#if MFX_DEBUG_DUMP_FRAME == MFX_DEBUG_YES - static FILE* m_f = 0; - if (NeedDumpBuffer()) { - const C2GraphicView& output_view = block->map().get(); - m_count_lock.lock(); - if (m_count) { - const uint8_t* srcY = output_view.data()[C2PlanarLayout::PLANE_Y]; - const uint8_t* srcU = output_view.data()[C2PlanarLayout::PLANE_U]; - const uint8_t* srcV = output_view.data()[C2PlanarLayout::PLANE_V]; - if (!m_f) { - m_f = fopen("/data/local/traces/decoder_frame.yuv", "w+"); - MFX_DEBUG_TRACE_STREAM("/data/local/traces/decoder_frame.yuv: create:" << m_f); - } - if (m_f) { - size_t copied_Y = 0, copied_U = 0; - copied_Y = fwrite(srcY, mfx_surface->Data.PitchLow * m_mfxVideoParams.mfx.FrameInfo.CropH, 1, m_f); - copied_U = fwrite(srcU, mfx_surface->Data.PitchLow * m_mfxVideoParams.mfx.FrameInfo.CropH / 2, 1, m_f); - MFX_DEBUG_TRACE_PRINTF("############# dumping #%d decoded buffer in size: %dx%d, Y:%zu, U:%zu #################", - m_count, mfx_surface->Data.PitchLow, m_mfxVideoParams.mfx.FrameInfo.CropH, copied_Y, copied_U); - if (copied_Y > 0 || copied_U > 0) - m_count--; - } - } - m_count_lock.unlock(); - } - m_count_lock.lock(); - if (m_count == 0 && m_f) { - fclose(m_f); - MFX_DEBUG_TRACE_MSG("dump file is closed"); - m_f = NULL; - } - m_count_lock.unlock(); -#endif worklet->output.buffers.push_back(out_buffer); block = nullptr; } diff --git a/c2_utils/include/mfx_debug.h b/c2_utils/include/mfx_debug.h index c4ecda8e..e41b8385 100755 --- a/c2_utils/include/mfx_debug.h +++ b/c2_utils/include/mfx_debug.h @@ -26,7 +26,6 @@ #define MFX_DEBUG MFX_DEBUG_NO // enables DEBUG output #define MFX_PERF MFX_DEBUG_NO // enables PERF output, doesn't depends on MFX_DEBUG #define MFX_ATRACE MFX_DEBUG_NO // enables systrace -#define MFX_DEBUG_DUMP_FRAME MFX_DEBUG_NO // enables write frame to file #define MFX_DEBUG_FILE MFX_DEBUG_NO // sends DEBUG and PERF output to file, otherwise to logcat From e26bfc929994172301968e4c7c00c7fa1fe3b2ee Mon Sep 17 00:00:00 2001 From: Lina Sun Date: Sat, 12 Oct 2024 13:53:54 +0000 Subject: [PATCH 2/2] Support dump of input & output for encoder & decoder Dump can be enabled by set property, detailed steps can be found in mfx_c2_encoder_component.cpp/mfx_c2_decoder_component.cpp, near InitDump(). Tracked-On: OAM-124732 Signed-off-by: Lina Sun --- c2_components/include/mfx_c2_component.h | 1 - .../include/mfx_c2_decoder_component.h | 13 + .../include/mfx_c2_encoder_component.h | 12 +- .../src/mfx_c2_decoder_component.cpp | 253 ++++++++++++++++++ .../src/mfx_c2_encoder_component.cpp | 166 ++++++++++-- .../android.hardware.media.c2@1.0-arm.policy | 1 + ...android.hardware.media.c2@1.0-arm64.policy | 1 + .../android.hardware.media.c2@1.0-x86.policy | 1 + ...ndroid.hardware.media.c2@1.0-x86_64.policy | 1 + c2_store/src/mfx_c2_store.cpp | 1 - c2_utils/include/mfx_c2_defs.h | 16 +- c2_utils/include/mfx_c2_utils.h | 11 +- c2_utils/include/mfx_c2_xml_parser.h | 2 - c2_utils/src/mfx_c2_utils.cpp | 4 +- c2_utils/src/mfx_c2_xml_parser.cpp | 24 +- 15 files changed, 451 insertions(+), 56 deletions(-) diff --git a/c2_components/include/mfx_c2_component.h b/c2_components/include/mfx_c2_component.h index 4d1ad096..2d4f0dd9 100755 --- a/c2_components/include/mfx_c2_component.h +++ b/c2_components/include/mfx_c2_component.h @@ -36,7 +36,6 @@ class MfxC2Component : public C2ComponentInterface, struct CreateConfig { int flags{0}; - bool dump_output{false}; uint32_t concurrent_instances{0}; bool low_power_mode{false}; }; diff --git a/c2_components/include/mfx_c2_decoder_component.h b/c2_components/include/mfx_c2_decoder_component.h index f9b26273..f97c46b8 100755 --- a/c2_components/include/mfx_c2_decoder_component.h +++ b/c2_components/include/mfx_c2_decoder_component.h @@ -29,6 +29,7 @@ #include "mfx_frame_pool_allocator.h" #include "mfx_gralloc_instance.h" #include "mfx_c2_setters.h" +#include "mfx_c2_utils.h" #include class MfxC2DecoderComponent : public MfxC2Component @@ -252,6 +253,18 @@ class MfxC2DecoderComponent : public MfxC2Component MFXVideoVPP* m_vpp; bool m_vppConversion = false; + std::unique_ptr m_outputWriter; + std::unique_ptr m_inputWriter; + + std::mutex m_dump_output_lock; + std::mutex m_dump_input_lock; + + uint32_t m_dump_count = 0; + // decoder output dump file number, during decoding one bitstream, if + // dump output multiple times, the first dumped file named xxx_0.yuv, + // second dumped file named xxx_1.yuv ... + uint32_t m_file_num = 0; + /* -----------------------C2Parameters--------------------------- */ std::shared_ptr m_name; std::shared_ptr m_kind; diff --git a/c2_components/include/mfx_c2_encoder_component.h b/c2_components/include/mfx_c2_encoder_component.h index ed2de8fb..4354e601 100755 --- a/c2_components/include/mfx_c2_encoder_component.h +++ b/c2_components/include/mfx_c2_encoder_component.h @@ -29,6 +29,7 @@ #include "mfx_c2_utils.h" #include "mfx_c2_vpp_wrapp.h" #include "mfx_c2_setters.h" +#include // Assumes all calls are done from one (working) thread, no sync is needed. // m_ctrlOnce accumulates subsequent changes for one next frame. @@ -202,8 +203,6 @@ class MfxC2EncoderComponent : public MfxC2Component std::shared_ptr m_c2Allocator; - std::unique_ptr m_outputWriter; - bool m_bHeaderSent{false}; mfxFrameSurface1 *m_encSrfPool; @@ -220,6 +219,15 @@ class MfxC2EncoderComponent : public MfxC2Component // Input frame info with width or height not 16byte aligned mfxFrameInfo m_mfxInputInfo; + std::unique_ptr m_outputWriter; + std::unique_ptr m_inputWriter; + + std::mutex m_dump_output_lock; + std::mutex m_dump_input_lock; + + uint32_t m_dump_count = 0; + uint32_t m_dump_frames_number = 0; //total frames to dump + /* -----------------------C2Parameters--------------------------- */ std::mutex m_c2ParameterMutex; std::shared_ptr m_name; diff --git a/c2_components/src/mfx_c2_decoder_component.cpp b/c2_components/src/mfx_c2_decoder_component.cpp index 140846db..175356ba 100755 --- a/c2_components/src/mfx_c2_decoder_component.cpp +++ b/c2_components/src/mfx_c2_decoder_component.cpp @@ -733,6 +733,67 @@ c2_status_t MfxC2DecoderComponent::Init() return MfxStatusToC2(mfx_res); } +// Dump input/output for decoder/encoder steps: +// +// 1. $adb shell +// 2. In adb shell, $setenforce 0 +// 3. In adb shell, +// +// Case 1) For decoder input dump: $setprop c2.decoder.dump.input true +// Case 2) For decoder output dump: $setprop c2.decoder.dump.output.number 10 +// Case 3) For encoder input dump: $setprop c2.encoder.dump.input.number 10 +// Case 4) For encoder output dump: $setprop c2.encoder.dump.output true +// +// yuv frames number to dump can be set as needed. +// +// 4. Run decode/encoder, when done, dumped files can be found in /data/local/traces. +// +// For cases 1), 3) and 4), for one bitsteam decode or one yuv file encode, can +// only dump once, dumped files are named in: +// "decoder/encoder name - year - month - day - hour -minute - second". +// Dumped files will not be automatically deleted/overwritten in next run, will +// need be deleted manually. +// +// For case 2), for one bitstream decode, output can be dumped multiple times +// during decode process, setprop need be run again for each dump, dumped files +// are named in "xxx_0.yuv", "xxx_1.yuv" ... +// +// 5. When viewing yuv frames, check surface width & height in logs. + +static void InitDump(std::unique_ptr& input_writer, + std::shared_ptr decoder_name) +{ + MFX_DEBUG_TRACE_FUNC; + + bool dump_input_enabled = false; + char* value = new char[20]; + if(property_get(DECODER_DUMP_INPUT_KEY, value, NULL) > 0) { + if(strcasecmp(value, "true") == 0) { + dump_input_enabled = true; + property_set(DECODER_DUMP_INPUT_KEY, NULL); + } + } + + if (dump_input_enabled) { + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + std::ostringstream file_name; + std::tm local_tm; + localtime_r(&now_c, &local_tm); + + file_name << decoder_name->m.value << "-" << + std::put_time(std::localtime(&now_c), "%Y-%m-%d-%H-%M-%S") << ".bin"; + + MFX_DEBUG_TRACE_STREAM("Decoder input dump is started to " << + MFX_C2_DUMP_DIR << "/" << MFX_C2_DUMP_DECODER_SUB_DIR << "/" + <(MFX_C2_DUMP_DIR, + std::vector({MFX_C2_DUMP_DECODER_SUB_DIR, + MFX_C2_DUMP_INPUT_SUB_DIR}), file_name.str()); + } +} + c2_status_t MfxC2DecoderComponent::DoStart() { MFX_DEBUG_TRACE_FUNC; @@ -753,6 +814,8 @@ c2_status_t MfxC2DecoderComponent::DoStart() mfx_res = InitSession(); if (MFX_ERR_NONE != mfx_res) break; + InitDump(m_inputWriter, m_name); + m_workingQueue.Start(); m_waitingQueue.Start(); } while(false); @@ -801,6 +864,16 @@ c2_status_t MfxC2DecoderComponent::DoStop(bool abort) m_c2Bitstream->GetFrameConstructor()->Close(); } + if(m_outputWriter.get() != NULL && m_outputWriter->IsOpen()) { + m_outputWriter->Close(); + } + m_outputWriter.reset(); + + if(m_inputWriter.get() != NULL && m_inputWriter->IsOpen()) { + m_inputWriter->Close(); + } + m_inputWriter.reset(); + m_OperationState = OperationState::STOPPED; return C2_OK; } @@ -2093,6 +2166,14 @@ void MfxC2DecoderComponent::DoWork(std::unique_ptr&& work) if (!m_bSetHdrStatic) UpdateHdrStaticInfo(); mfxBitstream *bs = m_c2Bitstream->GetFrameConstructor()->GetMfxBitstream().get(); + + { + std::lock_guard lock(m_dump_input_lock); + if (m_inputWriter.get() != NULL && bs != NULL && bs->DataLength > 0) { + m_inputWriter->Write(bs->Data, bs->DataLength); + } + } + MfxC2FrameOut frame_out; do { // check bitsream is empty @@ -2266,6 +2347,170 @@ void MfxC2DecoderComponent::Drain(std::unique_ptr&& work) } } +const u_int16_t ytile_width = 16; +const u_int16_t ytile_height = 32; +static void one_ytiled_to_linear(const unsigned char *src, char *dst, u_int16_t x, u_int16_t y, + u_int16_t width, u_int16_t height, uint32_t offset) +{ + // x and y follow linear + u_int32_t count = x + y * width / ytile_width; + + for (int j = 0; j < ytile_width * ytile_height; j += ytile_width) { + memcpy(dst + offset + width * ytile_height * y + width * j / ytile_width + x * ytile_width, + src + offset + j + ytile_width * ytile_height * count, ytile_width); + } +} + +static void* ytiled_to_linear(uint32_t total_size, uint32_t y_size, uint32_t stride, + const unsigned char *src) +{ + char* dst = (char*)malloc(total_size * 2); + if (NULL == dst) return NULL; + + memset(dst, 0, total_size * 2); + + u_int16_t height = y_size / stride; + + // Y + u_int16_t y_hcount = height / ytile_height + (height % ytile_height != 0); + for (u_int16_t x = 0; x < stride / ytile_width; x ++) { + for (u_int16_t y = 0; y < y_hcount; y ++) { + one_ytiled_to_linear(src, dst, x, y, stride, height, 0); + } + } + + // UV + u_int16_t uv_hcount = (height / ytile_height / 2) + (height % (ytile_height * 2) != 0); + for (u_int16_t x = 0; x < stride / ytile_width; x ++) { + for (u_int16_t y = 0; y < uv_hcount; y ++) { + one_ytiled_to_linear(src, dst, x, y, stride, height / 2, y_size); + } + } + + return dst; +} + +static bool NeedDumpOutput(uint32_t& dump_count, + std::unique_ptr& output_writer, + std::shared_ptr decoder_name, + uint32_t& file_num) +{ + MFX_DEBUG_TRACE_FUNC; + bool result = false; + char* value = new char[20]; + unsigned int frame_number = 0; + + if(property_get(DECODER_DUMP_OUTPUT_KEY, value, NULL) > 0) { + std::stringstream strValue; + strValue << value; + strValue >> frame_number; + } + + if (dump_count) { + delete[] value; + result = true; + } else { + delete[] value; + if (frame_number > 0) { + property_set(DECODER_DUMP_OUTPUT_KEY, NULL); + + std::ostringstream file_name; + file_name << decoder_name->m.value << "frame_" << std::to_string(file_num) << ".yuv"; + + MFX_DEBUG_TRACE_STREAM("Decoder output dump is started to " << + MFX_C2_DUMP_DIR << "/" << MFX_C2_DUMP_DECODER_SUB_DIR << "/" + <(MFX_C2_DUMP_DIR, + std::vector({MFX_C2_DUMP_DECODER_SUB_DIR, + MFX_C2_DUMP_OUTPUT_SUB_DIR}), file_name.str()); + + if(output_writer) { + dump_count = frame_number; + file_num ++; + MFX_DEBUG_TRACE_PRINTF("--------triggered to dump %d buffers---------", frame_number); + result = true; + } else { + MFX_DEBUG_TRACE_PRINTF("create output writer failed"); + result = false; + } + } + } + return result; +} + +static void DumpOutput(std::shared_ptr block, + std::shared_ptr mfx_surface, + uint32_t& dump_count, mfxVideoParam mfxVideoParams, + std::unique_ptr& output_writer) +{ + MFX_DEBUG_TRACE_FUNC; + static std::ofstream dump_stream; + + const C2GraphicView& output_view = block->map().get(); + + if (dump_count) { + const unsigned char* srcY = (const unsigned char*)output_view.data()[C2PlanarLayout::PLANE_Y]; + const unsigned char* srcUV = (const unsigned char*)output_view.data()[C2PlanarLayout::PLANE_U]; + + if (output_writer && srcY != NULL && srcUV != NULL) { + if(MFX_IOPATTERN_OUT_VIDEO_MEMORY == mfxVideoParams.IOPattern) { + const uint32_t align_width = 128; + const uint32_t align_height = 32; + + uint32_t surface_width = mfx_surface->Info.Width % align_width == 0? mfx_surface->Info.Width : + (mfx_surface->Info.Width / align_width + 1) * align_width; + uint32_t surface_height = mfx_surface->Info.Height % align_height == 0? mfx_surface->Info.Height : + (mfx_surface->Info.Height / align_height + 1) * align_height; + + uint32_t pix_len = (MFX_FOURCC_P010 == mfx_surface->Info.FourCC) ? 2 : 1; + + uint32_t total_size = surface_width * pix_len * surface_height * 3 / 2; + uint32_t y_size = surface_width * pix_len * surface_height; + uint32_t stride = surface_width * pix_len; + + unsigned char* srcY_linear = (unsigned char *)ytiled_to_linear(total_size, + y_size, stride, (const unsigned char *)srcY); + + if (NULL != srcY_linear) { + + output_writer->Write(srcY_linear, total_size); + free(srcY_linear); + srcY_linear = NULL; + + dump_count --; + + MFX_DEBUG_TRACE_PRINTF("######## dumping #%d to last decoded buffer in size: %dx%d ########", + dump_count, surface_width, surface_height); + } + } else { // IOPattern is system memory + if (NULL != srcY && NULL != srcUV) { + output_writer->Write(srcY, mfx_surface->Data.PitchLow * mfxVideoParams.mfx.FrameInfo.CropH); + output_writer->Write(srcUV, mfx_surface->Data.PitchLow * mfxVideoParams.mfx.FrameInfo.CropH / 2); + + uint32_t dump_width = (MFX_FOURCC_P010 == mfx_surface->Info.FourCC) ? + mfx_surface->Data.PitchLow / 2 : mfx_surface->Data.PitchLow; + + dump_count --; + + MFX_DEBUG_TRACE_PRINTF("######## dumping #%d to last decoded buffer in size: %dx%d ########", + dump_count, dump_width, mfxVideoParams.mfx.FrameInfo.CropH); + + } + } + } + } + + if (dump_count == 0 && output_writer.get() != NULL) { + output_writer->Close(); + output_writer.reset(); + + MFX_DEBUG_TRACE_MSG("Output writer reset"); + } + + return; +} + void MfxC2DecoderComponent::WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint sync_point) { MFX_DEBUG_TRACE_FUNC; @@ -2424,6 +2669,14 @@ void MfxC2DecoderComponent::WaitWork(MfxC2FrameOut&& frame_out, mfxSyncPoint syn } m_updatingC2Configures.clear(); + { + std::lock_guard lock(m_dump_output_lock); + + if (NeedDumpOutput(m_dump_count, m_outputWriter, m_name, m_file_num)) { + DumpOutput(block, mfx_surface, m_dump_count, m_mfxVideoParams, m_outputWriter); + } + } + worklet->output.buffers.push_back(out_buffer); block = nullptr; } diff --git a/c2_components/src/mfx_c2_encoder_component.cpp b/c2_components/src/mfx_c2_encoder_component.cpp index 5278935f..e62e834b 100755 --- a/c2_components/src/mfx_c2_encoder_component.cpp +++ b/c2_components/src/mfx_c2_encoder_component.cpp @@ -604,6 +604,101 @@ c2_status_t MfxC2EncoderComponent::Init() return MfxStatusToC2(mfx_res); } +// Dump input/output for decoder/encoder steps: +// +// 1. $adb shell +// 2. In adb shell, $setenforce 0 +// 3. In adb shell, +// +// Case 1) For decoder input dump: $setprop c2.decoder.dump.input true +// Case 2) For decoder output dump: $setprop c2.decoder.dump.output.number 10 +// Case 3) For encoder input dump: $setprop c2.encoder.dump.input.number 10 +// Case 4) For encoder output dump: $setprop c2.encoder.dump.output true +// +// yuv frames number to dump can be set as needed. +// +// 4. Run decode/encoder, when done, dumped files can be found in /data/local/traces. +// +// For cases 1), 3) and 4), for one bitsteam decode or one yuv file encode, can +// only dump once, dumped files are named in: +// "decoder/encoder name - year - month - day - hour -minute - second". +// Dumped files will not be automatically deleted/overwritten in next run, will +// need be deleted manually. +// +// For case 2), for one bitstream decode, output can be dumped multiple times +// during decode process, setprop need be run again for each dump, dumped files +// are named in "xxx_0.yuv", "xxx_1.yuv" ... +// +// 5. When viewing yuv frames, check surface width & height in logs. + +static void InitDump(std::unique_ptr& output_writer, + std::unique_ptr& input_writer, + uint32_t& dump_frames_number, + std::shared_ptr encoder_name) +{ + MFX_DEBUG_TRACE_FUNC; + + bool dump_output_enabled = false; + bool dump_input_enabled = false; + char* value = new char[20]; + + if(property_get(ENCODER_DUMP_OUTPUT_KEY, value, NULL) > 0) { + if(strcasecmp(value, "true") == 0) { + dump_output_enabled = true; + property_set(ENCODER_DUMP_OUTPUT_KEY, NULL); + } + } + + memset(value, sizeof(value), 0); + + if(property_get(ENCODER_DUMP_INPUT_KEY, value, NULL) > 0) { + std::stringstream strValue; + strValue << value; + strValue >> dump_frames_number; + + if(dump_frames_number > 0) { + dump_input_enabled = true; + property_set(ENCODER_DUMP_INPUT_KEY, NULL); + } + } + + if (dump_output_enabled || dump_input_enabled) { + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + std::time_t now_c = std::chrono::system_clock::to_time_t(now); + std::ostringstream file_name; + std::tm local_tm; + localtime_r(&now_c, &local_tm); + + // make dump directory and create dump file + if(dump_output_enabled) { + file_name << encoder_name->m.value << "-" << + std::put_time(std::localtime(&now_c), "%Y-%m-%d-%H-%M-%S") << ".bin"; + + MFX_DEBUG_TRACE_STREAM("Encoder output dump is started to " << + MFX_C2_DUMP_DIR << "/" << MFX_C2_DUMP_ENCODER_SUB_DIR << "/" << + MFX_C2_DUMP_OUTPUT_SUB_DIR << "/" << file_name.str()); + + output_writer = std::make_unique(MFX_C2_DUMP_DIR, + std::vector({MFX_C2_DUMP_ENCODER_SUB_DIR, + MFX_C2_DUMP_OUTPUT_SUB_DIR}), file_name.str()); + } + + if(dump_input_enabled) { + file_name.str(""); + file_name << encoder_name->m.value << "-" << + std::put_time(std::localtime(&now_c), "%Y-%m-%d-%H-%M-%S") << ".yuv"; + + MFX_DEBUG_TRACE_STREAM("Encoder input dump is started to " << + MFX_C2_DUMP_DIR << "/" << MFX_C2_DUMP_ENCODER_SUB_DIR << "/" << + MFX_C2_DUMP_INPUT_SUB_DIR << "/" << file_name.str()); + + input_writer = std::make_unique(MFX_C2_DUMP_DIR, + std::vector({MFX_C2_DUMP_ENCODER_SUB_DIR, + MFX_C2_DUMP_INPUT_SUB_DIR}), file_name.str()); + } + } +} + c2_status_t MfxC2EncoderComponent::DoStart() { MFX_DEBUG_TRACE_FUNC; @@ -653,27 +748,11 @@ c2_status_t MfxC2EncoderComponent::DoStart() } m_bAllocatorSet = allocator_required; } - m_workingQueue.Start(); - m_waitingQueue.Start(); - if (m_createConfig.dump_output) { - - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - std::time_t now_c = std::chrono::system_clock::to_time_t(now); - std::ostringstream oss; - std::tm local_tm; - localtime_r(&now_c, &local_tm); - - oss << m_name << "-" << std::put_time(std::localtime(&now_c), "%Y%m%d%H%M%S") << ".bin"; - - MFX_DEBUG_TRACE_STREAM("Encoder output dump is started to " << - MFX_C2_DUMP_DIR << "/" << MFX_C2_DUMP_OUTPUT_SUB_DIR << "/" << - oss.str()); - - m_outputWriter = std::make_unique(MFX_C2_DUMP_DIR, - std::vector({MFX_C2_DUMP_OUTPUT_SUB_DIR}), oss.str()); - } + InitDump(m_outputWriter, m_inputWriter, m_dump_frames_number, m_name); + m_workingQueue.Start(); + m_waitingQueue.Start(); } while(false); return C2_OK; @@ -705,8 +784,16 @@ c2_status_t MfxC2EncoderComponent::DoStop(bool abort) FreeEncoder(); + if(m_outputWriter.get() != NULL && m_outputWriter->IsOpen()) { + m_outputWriter->Close(); + } m_outputWriter.reset(); + if(m_inputWriter.get() != NULL && m_inputWriter->IsOpen()) { + m_inputWriter->Close(); + } + m_inputWriter.reset(); + return C2_OK; } @@ -1432,6 +1519,37 @@ void MfxC2EncoderComponent::DoWork(std::unique_ptr&& work) } } + { + std::lock_guard lock(m_dump_input_lock); + + if (m_inputWriter.get() != NULL && m_dump_count < m_dump_frames_number + && MFX_IOPATTERN_IN_SYSTEM_MEMORY == m_mfxVideoParamsConfig.IOPattern + && (MFX_FOURCC_NV12 == m_mfxVideoParamsState.mfx.FrameInfo.FourCC + || MFX_FOURCC_P010 == m_mfxVideoParamsState.mfx.FrameInfo.FourCC)) { + + mfxFrameSurface1* mfx_surface = mfx_frame_in.GetMfxFrameSurface(); + const uint8_t* srcY = mfx_surface->Data.Y; + const uint8_t* srcUV = mfx_surface->Data.UV; + + if (NULL != srcY && NULL != srcUV) { + m_inputWriter->Write(srcY, mfx_surface->Data.PitchLow * mfx_surface->Info.CropH); + m_inputWriter->Write(srcUV, mfx_surface->Data.PitchLow * mfx_surface->Info.CropH / 2); + + uint32_t dump_width = (MFX_FOURCC_P010 == m_mfxVideoParamsState.mfx.FrameInfo.FourCC) ? + mfx_surface->Data.PitchLow / 2 : mfx_surface->Data.PitchLow; + + m_dump_count ++; + + MFX_DEBUG_TRACE_PRINTF("######## dumping #%d encoder input buffer in size: %dx%d ########", + m_dump_count, dump_width, mfx_surface->Info.CropH); + } + + if(m_dump_count == m_dump_frames_number) { + m_inputWriter->Close(); + } + } + } + MfxC2BitstreamOut mfx_bitstream; res = AllocateBitstream(work, &mfx_bitstream); if(C2_OK != res) break; @@ -1610,9 +1728,13 @@ void MfxC2EncoderComponent::WaitWork(std::unique_ptr&& work, else { MFX_DEBUG_TRACE_STREAM(NAMED(mfx_bitstream->DataOffset) << NAMED(mfx_bitstream->DataLength)); - if (m_outputWriter && mfx_bitstream->DataLength > 0) { - m_outputWriter->Write(mfx_bitstream->Data + mfx_bitstream->DataOffset, - mfx_bitstream->DataLength); + { + std::lock_guard lock(m_dump_output_lock); + + if (m_outputWriter.get() != NULL && mfx_bitstream->DataLength > 0) { + m_outputWriter->Write(mfx_bitstream->Data + mfx_bitstream->DataOffset, + mfx_bitstream->DataLength); + } } C2ConstLinearBlock const_linear = bit_stream.GetC2LinearBlock()->share( diff --git a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm.policy b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm.policy index 9042cd77..408121d2 100644 --- a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm.policy +++ b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm.policy @@ -64,6 +64,7 @@ restart_syscall: 1 rt_sigreturn: 1 getrandom: 1 madvise: 1 +mkdirat: 1 # crash dump policy additions sigreturn: 1 diff --git a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm64.policy b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm64.policy index 5d0284f6..241d6385 100644 --- a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm64.policy +++ b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-arm64.policy @@ -60,6 +60,7 @@ restart_syscall: 1 rt_sigreturn: 1 getrandom: 1 madvise: 1 +mkdirat: 1 # crash dump policy additions clock_gettime: 1 diff --git a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86.policy b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86.policy index 50edbde8..8547727d 100644 --- a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86.policy +++ b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86.policy @@ -63,6 +63,7 @@ uname: 1 memfd_create: 1 ftruncate: 1 ftruncate64: 1 +mkdirat: 1 # Required by AddressSanitizer gettid: 1 diff --git a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86_64.policy b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86_64.policy index 0c196092..e5581eed 100644 --- a/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86_64.policy +++ b/c2_store/seccomp_policy/android.hardware.media.c2@1.0-x86_64.policy @@ -63,6 +63,7 @@ uname: 1 memfd_create: 1 ftruncate: 1 ftruncate64: 1 +mkdirat: 1 # Required by AddressSanitizer gettid: 1 diff --git a/c2_store/src/mfx_c2_store.cpp b/c2_store/src/mfx_c2_store.cpp index 38103cdc..b951febe 100755 --- a/c2_store/src/mfx_c2_store.cpp +++ b/c2_store/src/mfx_c2_store.cpp @@ -327,7 +327,6 @@ c2_status_t MfxC2ComponentStore::readConfigFile() MfxC2Component::CreateConfig config; config.flags = flags; - config.dump_output = m_xmlParser.dumpOutputEnabled(name.c_str()); config.concurrent_instances = m_xmlParser.getConcurrentInstances(name.c_str()); config.low_power_mode = m_xmlParser.getLowPowerMode(name.c_str()); diff --git a/c2_utils/include/mfx_c2_defs.h b/c2_utils/include/mfx_c2_defs.h index 48809dad..857b7ab5 100755 --- a/c2_utils/include/mfx_c2_defs.h +++ b/c2_utils/include/mfx_c2_defs.h @@ -34,8 +34,20 @@ #define MFX_C2_CONFIG_XML_FILE_NAME "media_codecs_intel_c2_video.xml" #define MFX_C2_CONFIG_XML_FILE_PATH "/vendor/etc" -#define MFX_C2_DUMP_DIR "/data/local/tmp" -#define MFX_C2_DUMP_OUTPUT_SUB_DIR "c2-output" +#define MFX_C2_DUMP_DIR "/data/local/traces" +#define MFX_C2_DUMP_DECODER_SUB_DIR "c2-intel-decoder" +#define MFX_C2_DUMP_ENCODER_SUB_DIR "c2-intel-encoder" +#define MFX_C2_DUMP_OUTPUT_SUB_DIR "output" +#define MFX_C2_DUMP_INPUT_SUB_DIR "input" + +// dump when dump frames number > 0 +#define DECODER_DUMP_OUTPUT_KEY "c2.decoder.dump.output.number" +// dump when property set to true +#define DECODER_DUMP_INPUT_KEY "c2.decoder.dump.input" +// dump when property set to true +#define ENCODER_DUMP_OUTPUT_KEY "c2.encoder.dump.output" +// dump when dump frames number > 0 +#define ENCODER_DUMP_INPUT_KEY "c2.encoder.dump.input.number" const c2_nsecs_t MFX_SECOND_NS = 1000000000; // 1e9 diff --git a/c2_utils/include/mfx_c2_utils.h b/c2_utils/include/mfx_c2_utils.h index 4006a2c5..cde6a964 100755 --- a/c2_utils/include/mfx_c2_utils.h +++ b/c2_utils/include/mfx_c2_utils.h @@ -187,9 +187,18 @@ class BinaryWriter stream_.write((const char*)data, length); } + bool IsOpen() + { + return stream_.is_open(); + } + + void Close() + { + stream_.close(); + } + private: std::ofstream stream_; - std::mutex m_mutex; }; // Writes YUV format frame to file.It useful for debug. diff --git a/c2_utils/include/mfx_c2_xml_parser.h b/c2_utils/include/mfx_c2_xml_parser.h index dd18cdbd..ae8675c6 100755 --- a/c2_utils/include/mfx_c2_xml_parser.h +++ b/c2_utils/include/mfx_c2_xml_parser.h @@ -50,7 +50,6 @@ class MfxXmlParser C2Component::kind_t getKind(const char *name); C2String getMediaType(const char *name); uint32_t getConcurrentInstances(const char *name); - bool dumpOutputEnabled(const char *name); bool getLowPowerMode(const char *name); private: @@ -61,7 +60,6 @@ class MfxXmlParser bool isEncoder; // whether this codec is an encoder or a decoder size_t order; // order of appearance in the file (starting from 0) std::map typeMap; // map of types supported by this codec - bool dump_output{false}; uint32_t concurrentInstance{0}; bool lowPowerMode{false}; }; diff --git a/c2_utils/src/mfx_c2_utils.cpp b/c2_utils/src/mfx_c2_utils.cpp index 54b66eac..a352e2e8 100755 --- a/c2_utils/src/mfx_c2_utils.cpp +++ b/c2_utils/src/mfx_c2_utils.cpp @@ -689,8 +689,6 @@ BinaryWriter::BinaryWriter(const std::string& dir, std::stringstream full_name; full_name << dir << "/"; - std::lock_guard lock(m_mutex); - for(const std::string& sub_dir : sub_dirs) { full_name << sub_dir; @@ -883,4 +881,4 @@ void ParseGop( if (iInterval) { iInterval = iInt; } -} \ No newline at end of file +} diff --git a/c2_utils/src/mfx_c2_xml_parser.cpp b/c2_utils/src/mfx_c2_xml_parser.cpp index 18a14342..93304f8f 100755 --- a/c2_utils/src/mfx_c2_xml_parser.cpp +++ b/c2_utils/src/mfx_c2_xml_parser.cpp @@ -94,18 +94,6 @@ uint32_t MfxXmlParser::getConcurrentInstances(const char *name) { return codec->second.concurrentInstance; } -bool MfxXmlParser::dumpOutputEnabled(const char *name) { - - MFX_DEBUG_TRACE_FUNC; - - auto codec = m_codecMap.find(name); - if (codec == m_codecMap.end()) { - MFX_DEBUG_TRACE_STREAM("codec " << name << "wasn't found"); - return false; - } - return codec->second.dump_output; -} - bool MfxXmlParser::getLowPowerMode(const char *name) { MFX_DEBUG_TRACE_FUNC; @@ -190,20 +178,12 @@ c2_status_t MfxXmlParser::addLimits(const char **attrs) { MFX_DEBUG_TRACE_MSG("concurrent-instances is null"); return C2_BAD_VALUE; } - } else if (strcmp(attrs[i], "dumpOutput") == 0) { - if (strcmp(attrs[++i], "value") == 0) { - m_currentCodec->second.dump_output = parseBoolean(attrs[++i]); - MFX_DEBUG_TRACE_PRINTF("m_currentCodec->second.dump_output = %d", m_currentCodec->second.dump_output); - } else { - MFX_DEBUG_TRACE_MSG("dumpOutput is null"); - return C2_BAD_VALUE; - } - } else if (strcmp(attrs[i], "lowPowerMode") == 0) { + } else if (strcmp(attrs[i], "low-power-mode") == 0) { if (strcmp(attrs[++i], "value") == 0) { m_currentCodec->second.lowPowerMode = parseBoolean(attrs[++i]); MFX_DEBUG_TRACE_PRINTF("m_currentCodec->second.lowPowerMode = %d ", m_currentCodec->second.lowPowerMode); } else { - MFX_DEBUG_TRACE_MSG("lowPowerMode is null"); + MFX_DEBUG_TRACE_MSG("low-power-mode is null"); return C2_BAD_VALUE; } }