Небольшая программа на C компилируется, но пытается импортировать функции из неправильных DLL

У меня есть небольшая программа на 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.c

LibLinkingTest.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

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]