У меня есть небольшая программа на C, которая использует 3 DLL. Он использует 8 функций из первой DLL. 5 функций из второй DLL. И 2 функции из 3-й DLL.
Проблема 1) Когда я открываю выходной исполняемый файл с помощью Dependency Walker, исполняемый файл пытается импортировать только 2 функции из каждой DLL. Это не может быть правдой.
Проблема 2) Что еще хуже, он пытается импортировать так же 2 функции из каждой DLL. Но только одна из DLL имеет эти две функции, которые она даже пытается импортировать. Таким образом, исполняемый файл выдает ошибку, говоря, что не может найти функцию. Но, конечно, это невозможно, потому что он ищет внутри DLL, которые явно не имеют этой функции.
Вопрос) Как мне это исправить? Я хочу открыть исполняемый файл с помощью Dependency Walker и увидеть, что он пытается импортировать 8 функций из первой DLL. 5 функций из второй DLL. И 2 функции из 3-й DLL. И я хочу видеть, что он пытается импортировать правильные функции из правильных DLL.
Надеюсь, кто-то может помочь мне, основываясь только на информации выше. Но если нет, надеюсь, я смогу отредактировать этот вопрос, и я включу все детали, включая исходный код программы (это один файл и кратко). Скриншоты Dependency Walker. Ссылки на файлы .h, .lib и .dll (они являются частью libx264). И скриншоты всех настроек в Visual Studio, которые необходимы для сборки программы без каких-либо ошибок.
Дополнительная информация …
Извините, я новичок в программировании на C, но постараюсь предоставить достаточно информации.
Ниже приведена программа на C, которая использует libx264 (или, возможно, API ffmpeg, который использует libx264 за кулисами), которая вручную рисует необработанные изображения RGB (как массивы uint8_t), передает их в кодировщик libx264, получает отдельные кадры x264 от кодировщика и записывает кадры x264 в файл (как массивы uint8_t). Эти кадры x264 затем могут быть переданы в декодер. Но эта программа просто кодирует.
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#pragma warning(disable : 4996)
static AVCodecContext *c = NULL;
static AVFrame *frame;
static AVPacket pkt;
static FILE *file;
struct SwsContext *sws_context = NULL;
static void ffmpeg_encoder_set_frame_yuv_from_rgb(uint8_t *rgb) {
const int in_linesize[1] = { 3 * c->width };
sws_context = sws_getCachedContext(sws_context,
c->width, c->height, AV_PIX_FMT_RGB24,
c->width, c->height, AV_PIX_FMT_YUV420P,
0, 0, 0, 0);
sws_scale(sws_context, (const uint8_t * const *)&rgb, in_linesize, 0,
c->height, frame->data, frame->linesize);
}
uint8_t* generate_rgb(int width, int height, int pts, uint8_t *rgb) {
int x, y, cur;
rgb = (uint8_t*)realloc(rgb, 3 * sizeof(uint8_t) * height * width);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
cur = 3 * (y * width + x);
rgb[cur + 0] = 0;
rgb[cur + 1] = 0;
rgb[cur + 2] = 0;
if ((frame->pts / 25) % 2 == 0) {
if (y < height / 2) {
if (x < width / 2) {
/* Black. */
}
else {
rgb[cur + 0] = 255;
}
}
else {
if (x < width / 2) {
rgb[cur + 1] = 255;
}
else {
rgb[cur + 2] = 255;
}
}
}
else {
if (y < height / 2) {
rgb[cur + 0] = 255;
if (x < width / 2) {
rgb[cur + 1] = 255;
}
else {
rgb[cur + 2] = 255;
}
}
else {
if (x < width / 2) {
rgb[cur + 1] = 255;
rgb[cur + 2] = 255;
}
else {
rgb[cur + 0] = 255;
rgb[cur + 1] = 255;
rgb[cur + 2] = 255;
}
}
}
}
}
return rgb;
}
/* Allocate resources and write header data to the output file. */
void ffmpeg_encoder_start(const char *filename, int codec_id, int fps, int width, int height) {
AVCodec *codec;
int ret;
codec = avcodec_find_encoder(codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
c->bit_rate = 400000;
c->width = width;
c->height = height;
c->time_base.num = 1;
c->time_base.den = fps;
c->keyint_min = 600;
c->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data, "preset", "slow", 0);
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
file = fopen(filename, "wb");
if (!file) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, c->pix_fmt, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
exit(1);
}
}
/*
Write trailing data to the output file
and free resources allocated by ffmpeg_encoder_start.
*/
void ffmpeg_encoder_finish(void) {
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
int got_output, ret;
do {
fflush(stdout);
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
fwrite(pkt.data, 1, pkt.size, file);
av_packet_unref(&pkt);
}
} while (got_output);
fwrite(endcode, 1, sizeof(endcode), file);
fclose(file);
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
av_frame_free(&frame);
}
/*
Encode one frame from an RGB24 input and save it to the output file.
Must be called after ffmpeg_encoder_start, and ffmpeg_encoder_finish
must be called after the last call to this function.
*/
void ffmpeg_encoder_encode_frame(uint8_t *rgb) {
int ret, got_output;
ffmpeg_encoder_set_frame_yuv_from_rgb(rgb);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
if (frame->pts == 1) {
frame->key_frame = 1;
frame->pict_type = AV_PICTURE_TYPE_I;
}
else {
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
}
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
fwrite(pkt.data, 1, pkt.size, file);
av_packet_unref(&pkt);
}
}
/* Represents the main loop of an application which generates one frame per loop. */
static void encode_example(const char *filename, int codec_id) {
int pts;
int width = 320;
int height = 240;
uint8_t *rgb = NULL;
ffmpeg_encoder_start(filename, codec_id, 25, width, height);
for (pts = 0; pts < 100; pts++) {
frame->pts = pts;
rgb = generate_rgb(width, height, pts, rgb);
ffmpeg_encoder_encode_frame(rgb);
}
ffmpeg_encoder_finish();
}
int main(void) {
avcodec_register_all();
encode_example("tmp.h264", AV_CODEC_ID_H264);
encode_example("tmp.mpg", AV_CODEC_ID_MPEG1VIDEO);
return 0;
}
Линия #pragma warning(disable : 4996)
игнорирует предупреждения об амортизации, которые рассматриваются как ошибки. Вы можете видеть, что некоторые из функций, которые я использую, помечены как устаревшие в заголовочных файлах. Я буду беспокоиться об этом позже, сейчас мне просто нужно что-то, что работает.
Файлы .h, .lib и .dll можно найти здесь: https://ffmpeg.zeranoe.com/builds/
На этом сайте есть несколько вариантов загрузки: Снимок экрана параметров загрузки
Я использую эту 64-битную бета-версию файлов .h, .lib и .dll. Вы также должны выбрать, хотите ли вы загружать версии файлов «Static», «Shared» или «Dev». «Общая» версия имеет файлы .dll. Версия «Dev» содержит файлы .h и .lib. Так что мне нужны были оба.
Мне посоветовали не публиковать скриншоты настроек в Visual Studio, но я кратко опишу то, что я сделал в Visual Studio, чтобы получить программу для сборки. Я должен был убедиться, что проект был установлен на 64-битный выход (он был 32-битным по умолчанию). Я должен был сказать Visual Studio, чтобы компилировать и связывать C, а не код C ++ (возможно, я сделал это, переименовав расширение файла исходного кода в .c вместо .cpp, я не помню). Я поместил папки с файлами .lib и .h в логическое место внутри папки моего проекта и добавил пути к местам, где Visual Studio будет искать файлы .lib и .h. Я также должен был специально назвать .lib-файлы, которые я использовал. После сборки я поместил DLL-файлы в ту же папку, что и скомпилированный исполняемый файл. Возможно, было что-то еще, но я не могу вспомнить.
Мне также посоветовали не делать скриншоты Dependency Walker, а вместо этого вставить вывод из команды:
dumpbin / import LibLinkingTest.exe
LibLinkingTest.exe — это имя исполняемого файла, который был скомпилирован из исходного кода C выше, на основе имени, которое я дал своему проекту. Вот вывод этой команды выше:
Microsoft (R) COFF / PE Dumper Версия 14.12.25835.0 Авторское право (C)
Корпорация Майкрософт. Все права защищены.Дамп файла LibLinkingTest.exe
Тип файла: EXECUTABLE IMAGE
Раздел содержит следующие импорта:
avcodec-58.dll 1400221D8 Import Address Table 1400226D8 Import Name Table 0 time date stamp 0 Index of first forwarder reference C sws_getCachedContext 1B sws_scale avutil-56.dll 1400221D8 Import Address Table 1400226D8 Import Name Table 0 time date stamp 0 Index of first forwarder reference C sws_getCachedContext 1B sws_scale swscale-5.dll 1400221D8 Import Address Table 1400226D8 Import Name Table 0 time date stamp 0 Index of first forwarder reference C sws_getCachedContext 1B sws_scale VCRUNTIME140D.dll 140022150 Import Address Table 140022650 Import Name Table 0 time date stamp 0 Index of first forwarder reference 31 __vcrt_LoadLibraryExW 2F __vcrt_GetModuleHandleW 25 __std_type_info_destroy_list 8 __C_specific_handler 2E __vcrt_GetModuleFileNameW ucrtbased.dll 140022270 Import Address Table 140022770 Import Name Table 0 time date stamp 0 Index of first forwarder reference 4D __p__commode 52B strcpy_s 527 strcat_s 68 __stdio_common_vsprintf_s 2C1 _seh_filter_dll 172 _initialize_onexit_table 2B4 _register_onexit_function E5 _execute_onexit_table C2 _crt_atexit C1 _crt_at_quick_exit 54A terminate 39B _wmakepath_s 3B7 _wsplitpath_s 563 wcscpy_s B5 _configthreadlocale 2CA _set_fmode 2B5 _register_thread_local_exe_atexit_callback 175 _initterm_e 174 _initterm 13D _get_initial_narrow_environment 171 _initialize_narrow_environment B6 _configure_narrow_argv 5B __setusermatherr 2C5 _set_app_type 2C2 _seh_filter_exe 5 _CrtDbgReportW 4 _CrtDbgReport 44F exit 504 realloc 5C __stdio_common_vfprintf 48A fwrite 47B fopen 468 fflush 459 fclose 35 __acrt_iob_func 2CD _set_new_mode A4 _cexit 9F _c_exit EA _exit 4A __p___argv 49 __p___argc KERNEL32.dll 140022000 Import Address Table 140022500 Import Name Table 0 time date stamp 0 Index of first forwarder reference 37D IsDebuggerPresent 45F RaiseException 3EB MultiByteToWideChar 605 WideCharToMultiByte 4CB RtlCaptureContext 4D2 RtlLookupFunctionEntry 4D9 RtlVirtualUnwind 5B4 UnhandledExceptionFilter 573 SetUnhandledExceptionFilter 2B1 GetProcAddress 1AF FreeLibrary 5D5 VirtualQuery 21B GetCurrentProcess 592 TerminateProcess 2B7 GetProcessHeap 34E HeapFree 384 IsProcessorFeaturePresent 34A HeapAlloc 449 QueryPerformanceCounter 21C GetCurrentProcessId 220 GetCurrentThreadId 2EC GetSystemTimeAsFileTime 367 InitializeSListHead 2D3 GetStartupInfoW 27A GetModuleHandleW 263 GetLastError
Резюме
1000 .00cfg 1000 .data 2000 .idata 3000 .pdata 3000 .rdata 1000 .reloc 1000 .rsrc A000 .text 10000 .textbss
Это связывает функции sws_getCachedContext
а также sws_scale
которые используются в исходном коде C выше с 3 DLL: avcodec-58.dll, avutil-56.dll и swscale-5.dll
Но функции sws_getCachedContext
а также sws_scale
присутствуют только в swscale-5.dll.
И нет никакого упоминания о 13 других функциях в исходном коде C выше, которые должны быть загружены из этих DLL.
Функции avcodec_find_encoder
, avcodec_alloc_context3
, avcodec_encode_video2
, avcodec_open2
, avcodec_close
, avcodec_register_all
, av_packet_unref
, а также av_init_packet
Исходный код C выше должен быть загружен из avcodec-58.dll.
Функции av_opt_set
, av_image_alloc
, av_free
, av_freep
, а также av_frame_free
Исходный код C выше должен быть загружен из avutil-56.dll.
Функции sws_getCachedContext
а также sws_scale
из исходного кода C, приведенного выше, должен быть загружен из swscale-5.dll (так что похоже, что он действительно получил это право).
Эти функции определенно присутствуют в этих библиотеках, потому что я могу видеть их внутри библиотек, используя Dependency Walker. Я уверен, что ни одна из этих функций статически не встроена в конечный исполняемый файл. Все эти функции должны быть загружены из DLL.
И мне посоветовали выложить журнал сборки. Вот журнал сборки:
Оптимизирующий компилятор Microsoft (R) C / C ++ версии 19.12.25835 для x64
Авторское право (C) Microsoft Corporation. Все права защищены.cl / c / ZI / W3 / WX- / диагностика: классика / sdl / Od / D _DEBUG / D _CONSOLE
/ D _UNICODE / D UNICODE / Гм / EHsc / RTC1 / MDd / GS / fp: точный
/ permissive- / Zc: wchar_t / Zc: forScope / Zc: inline /Fo»x64\Debug\»/Fd»x64\Debug\vc141.pdb «/ Gd / TC / errorReport: prompt LibLinkingTest.cLibLinkingTest.c
Инкрементальный компоновщик Microsoft (R), версия 14.12.25835.0
Авторское право (C) Microsoft Corporation. Все права защищены.«/OUT:C:\Users\me\Desktop\Programming\Windows\VS2017\LibLinkingTest\x64\Debug\LibLinkingTest.exe»/INCREMENTAL avcodec.lib avdevice.lib avfilter.lib avformat.lib
avutil.lib postproc.lib swresample.lib swscale.lib kernel32.lib
user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib
shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
/ MANIFEST «/ MANIFESTUAC: level = ‘asInvoker’ uiAccess = ‘false'» / manifest: embed / DEBUG: FASTLINK
«/PDB:C:\Users\me\Desktop\Programming\Windows\VS2017\LibLinkingTest\x64\Debug\LibLinkingTest.pdb»/SUBSYSTEM:CONSOLE / TLBID: 1 / DYNAMICBASE / NXCOMPAT
«/IMPLIB:C:\Users\me\Desktop\Programming\Windows\VS2017\LibLinkingTest\x64\Debug\LibLinkingTest.lib»/MACHINE:X64 x64 \ Debug \ LibLinkingTest.obj x64 \ Debug \ stdafx.obj
LibLinkingTest.vcxproj ->
C: \ Users \ Me \ Desktop \ Программирование \ Windows \ VS2017 \ LibLinkingTest \ x64 \ Debug \ LibLinkingTest.exe
Задача ещё не решена.
Других решений пока нет …