Skip to content

Commit e1193d1

Browse files
committed
feat: add Rust FFmpeg MP4 demuxer with compile-time switch
Replace GPAC-based MP4 demuxer with FFmpeg-based implementation in Rust using rsmpeg, activated via -DWITH_FFMPEG=ON. GPAC path remains default and untouched when FFmpeg is not enabled. Architecture: - Rust core (demuxer/mp4.rs): opens MP4 via rsmpeg, classifies tracks, dispatches packets to C bridge functions - FFI exports (mp4_ffmpeg_exports.rs): ccxr_processmp4/ccxr_dumpchapters callable from C - C bridge (mp4_rust_bridge.c): flat FFI-safe wrappers around existing do_NAL, process608, dtvcc_process_data, store_hdcc, encode_sub Supports AVC/H.264, HEVC/H.265, CEA-608, CEA-708, and tx3g tracks. Parses SPS/PPS/VPS from extradata for proper caption extraction. Build: cmake -DWITH_FFMPEG=ON -DWITH_OCR=ON -DWITH_HARDSUBX=ON ../src CI: fixed Linux cmake_ffmpeg_mp4 job, added macOS cmake_ffmpeg_mp4 job
1 parent 0cc314c commit e1193d1

File tree

18 files changed

+1254
-5
lines changed

18 files changed

+1254
-5
lines changed

.github/workflows/build_linux.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
runs-on: ubuntu-latest
8585
steps:
8686
- name: Install dependencies
87-
run: sudo apt update && sudo apt-get install libgpac-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev
87+
run: sudo apt update && sudo apt-get install libgpac-dev libtesseract-dev libleptonica-dev libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev libswresample-dev libswscale-dev
8888
- uses: actions/checkout@v6
8989
- name: cmake (default GPAC build)
9090
run: mkdir build && cd build && cmake ../src
@@ -94,7 +94,7 @@ jobs:
9494
- name: Display version information (GPAC build)
9595
run: ./build/ccextractor --version
9696
- name: cmake (FFmpeg MP4 build)
97-
run: mkdir build_ffmpeg && cd build_ffmpeg && cmake -DUSE_FFMPEG_MP4=ON ../src
97+
run: mkdir build_ffmpeg && cd build_ffmpeg && cmake -DWITH_FFMPEG=ON -DWITH_OCR=ON -DWITH_HARDSUBX=ON ../src
9898
- name: build (FFmpeg MP4 build)
9999
run: make -j$(nproc)
100100
working-directory: build_ffmpeg

.github/workflows/build_mac.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ jobs:
107107
working-directory: build
108108
- name: Display version information
109109
run: ./build/ccextractor --version
110+
cmake_ffmpeg_mp4:
111+
runs-on: macos-latest
112+
steps:
113+
- uses: actions/checkout@v6
114+
- name: Install dependencies
115+
run: brew install pkg-config gpac ffmpeg tesseract leptonica
116+
- name: cmake (FFmpeg MP4 build)
117+
run: |
118+
mkdir build && cd build
119+
cmake -DWITH_FFMPEG=ON -DWITH_OCR=ON -DWITH_HARDSUBX=ON ../src
120+
- name: build
121+
run: make -j$(nproc)
122+
working-directory: build
123+
- name: Display version information
124+
run: ./build/ccextractor --version
110125
build_shell_hardsubx:
111126
# Test build.command with -hardsubx flag (burned-in subtitle extraction)
112127
runs-on: macos-latest

src/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ if (PKG_CONFIG_FOUND AND WITH_FFMPEG)
196196

197197
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
198198
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_HARDSUBX")
199+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG_MP4")
200+
201+
pkg_check_modules (SWRESAMPLE libswresample)
202+
if (SWRESAMPLE_FOUND)
203+
set (EXTRA_LIBS ${EXTRA_LIBS} ${SWRESAMPLE_LIBRARIES})
204+
set (EXTRA_INCLUDES ${EXTRA_INCLUDES} ${SWRESAMPLE_INCLUDE_DIRS})
205+
endif()
199206
endif (PKG_CONFIG_FOUND AND WITH_FFMPEG)
200207

201208
########################################################

src/ccextractor.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,23 @@ int start_ccx()
222222
ret = tmp;
223223
break;
224224
case CCX_SM_MP4:
225-
mprint("\rAnalyzing data with GPAC (MP4 library)\n");
226-
close_input_file(ctx); // No need to have it open. GPAC will do it for us
227-
if (ctx->current_file == -1) // We don't have a file to open, must be stdin, and GPAC is incompatible with stdin
225+
close_input_file(ctx); // No need to have it open. The demuxer will do it for us
226+
if (ctx->current_file == -1) // We don't have a file to open, must be stdin
228227
{
229228
fatal(EXIT_INCOMPATIBLE_PARAMETERS, "MP4 requires an actual file, it's not possible to read from a stream, including stdin.\n");
230229
}
230+
#ifdef ENABLE_FFMPEG_MP4
231+
mprint("\rAnalyzing data with FFmpeg (MP4 demuxer)\n");
232+
if (ccx_options.extract_chapters)
233+
{
234+
tmp = ccxr_dumpchapters(ctx, ctx->inputfile[ctx->current_file]);
235+
}
236+
else
237+
{
238+
tmp = ccxr_processmp4(ctx, ctx->inputfile[ctx->current_file]);
239+
}
240+
#else
241+
mprint("\rAnalyzing data with GPAC (MP4 library)\n");
231242
if (ccx_options.extract_chapters)
232243
{
233244
tmp = dumpchapters(ctx, &ctx->mp4_cfg, ctx->inputfile[ctx->current_file]);
@@ -236,6 +247,7 @@ int start_ccx()
236247
{
237248
tmp = processmp4(ctx, &ctx->mp4_cfg, ctx->inputfile[ctx->current_file]);
238249
}
250+
#endif
239251
if (ccx_options.print_file_reports)
240252
print_file_report(ctx);
241253
if (!ret)

src/lib_ccx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ if (WITH_FFMPEG)
3939

4040
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG")
4141
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_HARDSUBX")
42+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_FFMPEG_MP4")
4243
endif (WITH_FFMPEG)
4344

4445
if (WITH_OCR)

src/lib_ccx/ccx_gpac_types.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Minimal GPAC-compatible type definitions for the FFmpeg MP4 bridge.
3+
* When ENABLE_FFMPEG_MP4 is defined and GPAC headers may not be available,
4+
* these provide the subset of GPAC types needed by the C bridge functions.
5+
*/
6+
#ifndef CCX_GPAC_TYPES_H
7+
#define CCX_GPAC_TYPES_H
8+
9+
#include <stdint.h>
10+
11+
#ifndef GPAC_VERSION_MAJOR
12+
/* Only define these if real GPAC headers are not included */
13+
14+
typedef uint8_t u8;
15+
typedef uint16_t u16;
16+
typedef uint32_t u32;
17+
typedef uint64_t u64;
18+
typedef int32_t s32;
19+
20+
#ifndef GF_4CC
21+
#define GF_4CC(a,b,c,d) ((((u32)a)<<24)|(((u32)b)<<16)|(((u32)c)<<8)|((u32)d))
22+
#endif
23+
24+
/* Minimal GF_AVCConfig - only fields used by process_avc_sample */
25+
typedef struct {
26+
u8 nal_unit_size;
27+
} GF_AVCConfig_Minimal;
28+
29+
/* Minimal GF_HEVCConfig - only fields used by process_hevc_sample */
30+
typedef struct {
31+
u8 nal_unit_size;
32+
} GF_HEVCConfig_Minimal;
33+
34+
/* Minimal GF_ISOSample - only fields used by process_*_sample */
35+
typedef struct {
36+
u32 dataLength;
37+
char *data;
38+
u64 DTS;
39+
u32 CTS_Offset;
40+
} GF_ISOSample_Minimal;
41+
42+
#endif /* GPAC_VERSION_MAJOR */
43+
44+
#endif /* CCX_GPAC_TYPES_H */

src/lib_ccx/ccx_mp4.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,12 @@
33

44
int processmp4(struct lib_ccx_ctx *ctx, struct ccx_s_mp4Cfg *cfg, char *file);
55
int dumpchapters(struct lib_ccx_ctx *ctx, struct ccx_s_mp4Cfg *cfg, char *file);
6+
unsigned char *ccdp_find_data(unsigned char *ccdp_atom_content, unsigned int len, unsigned int *cc_count);
7+
8+
#ifdef ENABLE_FFMPEG_MP4
9+
/* Rust FFmpeg MP4 demuxer entry points */
10+
int ccxr_processmp4(struct lib_ccx_ctx *ctx, const char *file);
11+
int ccxr_dumpchapters(struct lib_ccx_ctx *ctx, const char *file);
12+
#endif
13+
614
#endif

0 commit comments

Comments
 (0)