diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca3f80d..e5effa7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,24 +14,63 @@ permissions: jobs: build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - runs-on: ubuntu-latest + shell: bash + - runs-on: macos-latest + shell: bash + - runs-on: windows-latest + shell: msys2 + runs-on: ${{matrix.runs-on}} + defaults: + run: + shell: ${{matrix.shell}} {0} steps: - uses: actions/checkout@v4 - name: Install dependencies + if: runner.os == 'Linux' run: | - sudo add-apt-repository ppa:xmake-io/xmake sudo apt-get -y update - sudo apt-get -y install xmake + sudo apt-get -y install meson + - name: Install dependencies + if: runner.os == 'macOS' + run: | + brew install meson + - uses: msys2/setup-msys2@v2 + if: runner.os == 'Windows' + - name: Install dependencies + if: runner.os == 'Windows' + run: | + pacman -Sy --noconfirm mingw-w64-x86_64-meson - name: Build run: | - xmake + sed -i -e"s/, 'linearasm'//g" meson.build + meson setup build -Db_coverage=true + meson compile -Cbuild + meson test -Cbuild + mv build/x264 build/${{matrix.runs-on}}-x264 || + mv build/x264.exe build/${{matrix.runs-on}}-x264.exe - uses: actions/upload-artifact@v4 if: ${{ ! startsWith(github.ref, 'refs/tags/') }} with: + name: artifact-${{matrix.runs-on}} path: | - x264 + build/*-x264* + + publish: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + steps: + - uses: actions/download-artifact@v4 + with: + pattern: artifact-* + merge-multiple: true + path: build - uses: softprops/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/') with: files: | - x264 + build/* diff --git a/README.md b/README.md index 45eabc5..af9f20f 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,79 @@ scripts/burn.js /the/path/of/352x288.yuv -- build/x264.out --input=352x288.yuv - ffplay build/out.264 ``` +## Usage + +See `--help`: + +```sh +sed -i -e"s/, 'linearasm'//g" meson.build +meson setup build/host +meson compile -Cbuild/host +build/host/x264 --help +``` + +Here are some details: + +### --disable-ddr-input/--disable-ddr-output + +There are two methods to pass input/output file to/from TI DSP: + +- CIO. for only debug, allow TI DSP read/write host machine filesystem, we can + get frame number from file size +- `loadRaw()/saveRaw()`. load/save a file from/to DDR2. We must tell frame + number + +By default, in TI DSP, it will enable DDR input/output. In PC, it always +read/write from itself's filesystem. + +```sh +$ scripts/burn.js -- build/x264.out --input=../../352x288.yuv --disable-ddr-input +# ... +../../352x288.yuv [info]: 352x288p 0:0 @ 25/1 fps (cfr) +x264 [info]: profile Constrained Baseline, level 1.3 +x264 [info]: frame I:1 Avg QP:29.00 size: 5403 +encoded 1 frames, 0.02 fps, 1080.60 kb/s +$ scripts/burn.js ../352x288.yuv -- build/x264.out --input=../../352x288.yuv --frames=1 +# ... +../../352x288.yuv [info]: 352x288p 0:0 @ 25/1 fps (cfr) +x264 [info]: profile Constrained Baseline, level 1.3 +x264 [info]: frame I:1 Avg QP:29.00 size: 5648 +encoded 1 frames, 0.50 fps, 1129.60 kb/s +``` + +### --input/--output + +In PC, related path is based on `$PWD`. In TI DSP, related path is based on the +directory of `x264.out`. + +```sh +$ build/host/x264 --input=../352x288.yuv +../352x288.yuv [info]: 352x288p 0:0 @ 25/1 fps (cfr) +x264 [info]: profile Constrained Baseline, level 1.3 +x264 [info]: frame I:1 Avg QP:29.00 size: 5403 +encoded 1 frames, inf fps, 1080.60 kb/s +``` + +If you use DDR input, it will ignore `--input`. however, `x264` get +`widthxheight` from `--input`. So the following commands are same: + +```sh +scripts/burn.js ../352x288.yuv -- build/x264.out --input=../../352x288.yuv --frames=1 +scripts/burn.js ../352x288.yuv -- build/x264.out --input=foo352x288bar.yuv --frames=1 +``` + +`scripts/burn.js ../352x288.yuv` will `loadRaw()` `../352x288.yuv` to DDR. +If the power is on, the step only need to be done once: + +```sh +scripts/burn.js ../352x288.yuv +scripts/burn.js -- build/x264.out --input=../../352x288.yuv --frames=1 +``` + +### Todo + +- Fix bug about 5648 != 5403 + ## Documents - codec diff --git a/input.c b/input.c index 0a7f067..8330754 100644 --- a/input.c +++ b/input.c @@ -100,7 +100,7 @@ typedef struct uint64_t frame_size; /* frame size in bytes*/ } input_hnd_t; -static int open_file(char *psz_filename, void **p_handle, video_info_t *info) { +static int open_file(char *psz_filename, void **p_handle, video_info_t *info, int b_ddr_input) { int i; char *p; const x264_cli_csp_t *csp; @@ -122,14 +122,14 @@ static int open_file(char *psz_filename, void **p_handle, video_info_t *info) { /* default color-space: I420 without high bit-depth */ info->csp = X264_CSP_I420; -#if 0 - if (!strcmp(psz_filename, "-")) - h->fh = stdin; - else - h->fh = fopen(psz_filename, "rb"); - if (h->fh == NULL) - return -1; -#endif + if (b_ddr_input == 0) { + if (!strcmp(psz_filename, "-")) + h->fh = stdin; + else + h->fh = fopen(psz_filename, "rb"); + if (h->fh == NULL) + return -1; + } csp = x264_cli_get_csp(info->csp); for (i = 0; i < csp->planes; i++) { @@ -140,6 +140,13 @@ static int open_file(char *psz_filename, void **p_handle, video_info_t *info) { } if (h->frame_size > 0) { + if (b_ddr_input == 0) { + uint64_t i_size; + fseek(h->fh, 0, SEEK_END); + i_size = ftell(h->fh); + fseek(h->fh, 0, SEEK_SET); + info->num_frames = i_size / h->frame_size; + } #ifdef DOWNSAMPLE info->num_frames /= SCALE * SCALE; #endif @@ -149,7 +156,7 @@ static int open_file(char *psz_filename, void **p_handle, video_info_t *info) { return 0; } -static int read_frame_internal(cli_pic_t *pic, input_hnd_t *h) { +static int read_frame_internal(cli_pic_t *pic, input_hnd_t *h, int b_ddr_input) { int error = 0; int i; int pixel_depth = x264_cli_csp_depth_factor(pic->img.csp); @@ -167,7 +174,11 @@ static int read_frame_internal(cli_pic_t *pic, input_hnd_t *h) { } plane_size *= SCALE * SCALE; #endif - buf = (void *)p_yuv; + if (b_ddr_input == 0) { + buf = malloc(pixel_depth * plane_size); + error |= fread(buf, pixel_depth, plane_size, h->fh) != plane_size; + } else + buf = (void *)p_yuv; #ifndef DOWNSAMPLE memcpy((void *)pic->img.plane[i], buf, plane_size); #elif DOWNSAMPLE == DOWNSAMPLE_BILINEAR @@ -183,29 +194,35 @@ static int read_frame_internal(cli_pic_t *pic, input_hnd_t *h) { #else #error wrong DOWNSAMPLE! #endif - p_yuv += pixel_depth * plane_size; + if (b_ddr_input == 0) + free(buf); + else + p_yuv += pixel_depth * plane_size; } return error; } -static int read_frame(cli_pic_t *pic, void *handle, int i_frame) { +static int read_frame(cli_pic_t *pic, void *handle, int i_frame, int b_ddr_input) { input_hnd_t *h = handle; - if (read_frame_internal(pic, h)) + if (b_ddr_input == 0 && i_frame > h->next_frame) + fseek(h->fh, i_frame * h->frame_size, SEEK_SET); + + if (read_frame_internal(pic, h, b_ddr_input)) return -1; h->next_frame = i_frame + 1; return 0; } -static int close_file(void *handle) { -#if 0 - input_hnd_t *h = handle; - if (!h || !h->fh) - return 0; - fclose(h->fh); - free(h); -#endif +static int close_file(void *handle, int b_ddr_input) { + if (b_ddr_input == 0) { + input_hnd_t *h = handle; + if (!h || !h->fh) + return 0; + fclose(h->fh); + free(h); + } return 0; } diff --git a/input.h b/input.h index 460c693..36e7a40 100644 --- a/input.h +++ b/input.h @@ -5,6 +5,7 @@ #ifndef X264_INPUT_H #define X264_INPUT_H +#include /* properties of the source given by the demuxer */ typedef struct { @@ -45,12 +46,12 @@ typedef struct typedef struct { - int (*open_file)(char *psz_filename, void **p_handle, video_info_t *info); + int (*open_file)(char *psz_filename, void **p_handle, video_info_t *info, int b_ddr_input); int (*picture_alloc)(cli_pic_t *pic, int csp, int width, int height); - int (*read_frame)(cli_pic_t *pic, void *handle, int i_frame); + int (*read_frame)(cli_pic_t *pic, void *handle, int i_frame, int b_ddr_input); int (*release_frame)(cli_pic_t *pic, void *handle); void (*picture_clean)(cli_pic_t *pic); - int (*close_file)(void *handle); + int (*close_file)(void *handle, int b_ddr_input); } cli_input_t; extern const cli_input_t cli_input; diff --git a/x264.c b/x264.c index 8012849..de669ed 100644 --- a/x264.c +++ b/x264.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "common/x264.h" #include "input.h" @@ -10,6 +11,8 @@ #include "extras/getopt.h" +#define DEFAULT_BUFFER_SIZE 256 + /* In microseconds */ #define UPDATE_INTERVAL 1000000 @@ -18,6 +21,8 @@ typedef struct { int i_seek; /* seek position of start encoding */ void *hin; /* input handle */ void *hout; /* output handle */ + int b_ddr_input; + int b_ddr_output; } cli_opt_t; /* logging and printing for within the cli system */ @@ -80,34 +85,95 @@ int main(int argc, char **argv) { /* clean up handles */ if (opt.hin) - cli_input.close_file(opt.hin); + cli_input.close_file(opt.hin, opt.b_ddr_input); if (opt.hout) cli_output.close_file(opt.hout, 0, 0); return ret; } -static char shortopts[] = "i:f:"; +static char shortopts[] = "hVf:i:o:I:O:1:0:"; static struct option longopts[] = { - {"input", required_argument, NULL, 'i'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, {"frames", required_argument, NULL, 'f'}, + {"input", required_argument, NULL, 'i'}, + {"output", required_argument, NULL, 'o'}, + {"disable-ddr-input", no_argument, NULL, 'I'}, + {"disable-ddr-output", no_argument, NULL, 'O'}, + {"ddr-input-address", required_argument, NULL, '1'}, + {"ddr-output-address", required_argument, NULL, '0'}, {NULL, 0, NULL, 0}}; +int print_help(const struct option *longopts) { + unsigned int i = 0; + struct option o = longopts[i]; + while (o.name != NULL) { + char name[DEFAULT_BUFFER_SIZE]; + char value[DEFAULT_BUFFER_SIZE + sizeof("(|)") - 1]; + char meta[DEFAULT_BUFFER_SIZE]; + char *str = meta; + + if (isascii(o.val)) + sprintf(name, "(--%s|-%c)", o.name, (char)o.val); + else + sprintf(name, "--%s", o.name); + + sprintf(meta, "%s", o.name); + do + *str = (char)toupper(*str); + while (*str++); + + if (o.has_arg == required_argument) + sprintf(value, " %s", meta); + else if (o.has_arg == optional_argument) + sprintf(value, "( %s)", meta); + else + value[0] = '\0'; + + printf(" [%s%s]", name, value); + + o = longopts[++i]; + } + return EXIT_SUCCESS; +} + static int parse(int argc, char **argv, x264_param_t *param, cli_opt_t *opt) { char *input_filename = "352x288.yuv"; char *output_filename = "out.264"; video_info_t info = {0}; int c; +#if defined(__TI_COMPILER_VERSION__) + opt->b_ddr_input = 1; + opt->b_ddr_output = 1; +#endif opt->b_progress = 1; info.num_frames = 1; while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch (c) { + case 'h': + printf("x264"); + print_help(longopts); + puts(""); + return 1; + case 'V': + puts("0.0.1"); + return 1; + case 'f': + info.num_frames = strtol(optarg, NULL, 0); + break; case 'i': input_filename = optarg; break; - case 'f': - info.num_frames = strtol(optarg, NULL, 0); + case 'o': + output_filename = optarg; + break; + case 'I': + opt->b_ddr_input = 0; + break; + case 'O': + opt->b_ddr_output = 0; break; default: return 1; @@ -131,7 +197,7 @@ static int parse(int argc, char **argv, x264_param_t *param, cli_opt_t *opt) { FAIL_IF_ERROR(cli_output.open_file(output_filename, &opt->hout), "could not open output file `%s'\n", output_filename) - FAIL_IF_ERROR(cli_input.open_file(input_filename, &opt->hin, &info), + FAIL_IF_ERROR(cli_input.open_file(input_filename, &opt->hin, &info, opt->b_ddr_input), "could not open input file `%s'\n", input_filename) x264_cli_log(input_filename, X264_LOG_INFO, "%dx%d%c %u:%u @ %u/%u fps (%cfr)\n", info.width, @@ -245,7 +311,7 @@ static int encode(x264_param_t *param, cli_opt_t *opt) { /* Encode frames */ for (; (i_frame < param->i_frame_total || !param->i_frame_total); i_frame++) { - if (cli_input.read_frame(&cli_pic, opt->hin, i_frame + opt->i_seek)) + if (cli_input.read_frame(&cli_pic, opt->hin, i_frame + opt->i_seek, opt->b_ddr_input)) break; x264_picture_init(&pic);