[
  {
    "path": ".gitattributes",
    "content": ". !text !filter !merge !diff\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: ffmpegwasm\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Remove\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom:\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nPlease provide a GitHub link or code snippet.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "## Security contact information\n\nTo report a security vulnerability, please use the\n[Tidelift security contact](https://tidelift.com/security).\nTidelift will coordinate the fix and disclosure.\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\njobs:\n  build-core:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Source Code\n        uses: actions/checkout@v2\n      - name: Update pkg-config database\n        run: sudo ldconfig\n      - name: Setup Docker Buildx\n        id: buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Cache build\n        id: cache-build\n        uses: actions/cache@v4\n        with:\n          path: build-cache-st\n          key: build-cache-st-v1-${{ hashFiles('Dockerfile', 'Makefile', 'build/*') }}\n          restore-keys: |\n            build-cache-st-v1-\n      - name: Build ffmpeg-core\n        run: make prd EXTRA_ARGS=\"--cache-from=type=local,src=build-cache-st --cache-to=type=local,dest=build-cache-st,mode=max\"\n      - name: Upload core\n        uses: actions/upload-artifact@v4\n        with:\n          name: ffmpeg-core\n          path: packages/core/dist/*\n  build-core-mt:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Source Code\n        uses: actions/checkout@v2\n      - name: Setup Docker Buildx\n        id: buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Cache build\n        id: cache-build\n        uses: actions/cache@v4\n        with:\n          path: build-cache-mt\n          key: build-cache-mt-v1-${{ hashFiles('Dockerfile', 'Makefile', 'build/*') }}\n          restore-keys: |\n            build-cache-v1-\n      - name: Build ffmpet-core-mt\n        run: make prd-mt EXTRA_ARGS=\"--cache-from=type=local,src=build-cache-mt --cache-to=type=local,dest=build-cache-mt,mode=max\"\n      - name: Upload core-mt\n        uses: actions/upload-artifact@v4\n        with:\n          name: ffmpeg-core-mt\n          path: packages/core-mt/dist/*\n  tests:\n    runs-on: ubuntu-latest\n    needs:\n      - build-core\n      - build-core-mt\n    steps:\n      - name: Checkout Source Code\n        uses: actions/checkout@v2\n      - name: Download ffmpeg-core\n        uses: actions/download-artifact@v4\n        with:\n          name: ffmpeg-core\n          path: packages/core/dist\n      - name: Download ffmpeg-core-mt\n        uses: actions/download-artifact@v4\n        with:\n          name: ffmpeg-core-mt\n          path: packages/core-mt/dist\n      - name: Use Node.js 18\n        uses: actions/setup-node@v2\n        with:\n          node-version: 18.x\n      - name: Cache dependencies\n        id: cache-dependencies\n        uses: actions/cache@v4\n        with:\n          path: node_modules\n          key: node-modules-${{ hashFiles('package-lock.json') }}\n          restore-keys: |\n            node-modules-\n      - name: Install dependencies\n        run: npm install\n      - name: Install Chrome\n        uses: browser-actions/setup-chrome@latest\n        with:\n          chrome-version: stable\n      - name: Run tests\n        env:\n          CHROME_HEADLESS: 1\n          CHROME_PATH: chrome\n          CHROME_FLAGS: \"--headless --disable-gpu --no-sandbox --enable-features=SharedArrayBuffer,CrossOriginIsolation\"\n          HEADERS: '{\"Cross-Origin-Opener-Policy\": \"same-origin\", \"Cross-Origin-Embedder-Policy\": \"require-corp\"}'\n        run: |\n          # Start test server with proper headers for all tests\n          npm run serve -- --headers \"$HEADERS\" &\n\n          # Increase wait time to ensure server is ready\n          sleep 15\n\n          # Verify headers and isolation status\n          echo \"Checking security headers and isolation status...\"\n          curl -v http://localhost:3000/tests/ffmpeg-core-st.test.html 2>&1 | grep -i \"cross-origin\"\n\n          # Run verification script first\n          echo \"Verifying browser environment...\"\n          cat << EOF > verify-browser.html\n          <!DOCTYPE html>\n          <html>\n          <head>\n            <meta http-equiv=\"Cross-Origin-Opener-Policy\" content=\"same-origin\">\n            <meta http-equiv=\"Cross-Origin-Embedder-Policy\" content=\"require-corp\">\n          </head>\n          <body>\n            <script>\n              console.log('SharedArrayBuffer available:', typeof SharedArrayBuffer !== 'undefined');\n              console.log('crossOriginIsolated:', window.crossOriginIsolated);\n              if (!window.crossOriginIsolated || typeof SharedArrayBuffer === 'undefined') {\n                throw new Error('Browser environment not properly configured for SharedArrayBuffer');\n              }\n            </script>\n          </body>\n          </html>\n          EOF\n\n          # Run single-threaded tests first\n          echo \"Running single-threaded tests...\"\n          npx mocha-headless-chrome \\\n            --args=\"$CHROME_FLAGS\" \\\n            -a no-sandbox \\\n            -f http://localhost:3000/tests/ffmpeg-core-st.test.html 2>&1 | tee st-core-test.log\n\n          npx mocha-headless-chrome \\\n            --args=\"$CHROME_FLAGS\" \\\n            -a no-sandbox \\\n            -f http://localhost:3000/tests/ffmpeg-st.test.html 2>&1 | tee st-test.log\n\n          # Run multi-threaded tests\n          echo \"Running multi-threaded tests...\"\n          # Create a test script to verify browser environment\n          cat << EOF > verify-browser.html\n          <!DOCTYPE html>\n          <html>\n          <head>\n            <title>Browser Environment Test</title>\n          </head>\n          <body>\n            <script>\n              console.log('SharedArrayBuffer available:', typeof SharedArrayBuffer !== 'undefined');\n              console.log('crossOriginIsolated:', window.crossOriginIsolated);\n            </script>\n          </body>\n          </html>\n          EOF\n\n          # Run the verification in Chrome\n          echo \"Verifying browser environment...\"\n          npx mocha-headless-chrome \\\n            --args=\"$CHROME_FLAGS --enable-features=SharedArrayBuffer,CrossOriginIsolation\" \\\n            -a no-sandbox \\\n            -f http://localhost:3000/verify-browser.html\n\n          # Run MT tests with verified configuration\n          npx mocha-headless-chrome \\\n            --args=\"$CHROME_FLAGS --enable-features=SharedArrayBuffer,CrossOriginIsolation\" \\\n            -a no-sandbox \\\n            -f http://localhost:3000/tests/ffmpeg-core-mt.test.html 2>&1 | tee mt-core-test.log\n\n          npx mocha-headless-chrome \\\n            --args=\"$CHROME_FLAGS --enable-features=SharedArrayBuffer,CrossOriginIsolation\" \\\n            -a no-sandbox \\\n            -f http://localhost:3000/tests/ffmpeg-mt.test.html 2>&1 | tee mt-test.log\n\n          # Display all logs for debugging\n          echo \"=== Test Logs ===\"\n          for log in *-test.log; do\n            echo \"Contents of $log:\"\n            cat $log\n          done\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ndist\n/.nyc_output\n.DS_Store\n\n# ide\n.idea/\n\n# Local Netlify folder\n.netlify\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"testdata\"]\n\tpath = testdata\n\turl = https://github.com/ffmpegwasm/testdata\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at jeromewus@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Check https://ffmpegwasm.netlify.app/docs/contribution/core\n"
  },
  {
    "path": "Dockerfile",
    "content": "# syntax=docker/dockerfile-upstream:master-labs\n\n# Base emsdk image with environment variables.\nFROM emscripten/emsdk:3.1.40 AS emsdk-base\nARG EXTRA_CFLAGS\nARG EXTRA_LDFLAGS\nARG FFMPEG_ST\nARG FFMPEG_MT\nENV INSTALL_DIR=/opt\n# We cannot upgrade to n6.0 as ffmpeg bin only supports multithread at the moment.\nENV FFMPEG_VERSION=n5.1.4\nENV CFLAGS=\"-I$INSTALL_DIR/include $CFLAGS $EXTRA_CFLAGS\"\nENV CXXFLAGS=\"$CFLAGS\"\nENV LDFLAGS=\"-L$INSTALL_DIR/lib $LDFLAGS $CFLAGS $EXTRA_LDFLAGS\"\nENV EM_PKG_CONFIG_PATH=$EM_PKG_CONFIG_PATH:$INSTALL_DIR/lib/pkgconfig:/emsdk/upstream/emscripten/system/lib/pkgconfig\nENV EM_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake\nENV PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$EM_PKG_CONFIG_PATH\nENV FFMPEG_ST=$FFMPEG_ST\nENV FFMPEG_MT=$FFMPEG_MT\nRUN apt-get update && \\\n      apt-get install -y pkg-config autoconf automake libtool ragel\n\n# Build x264\nFROM emsdk-base AS x264-builder\nENV X264_BRANCH=4-cores\nADD https://github.com/ffmpegwasm/x264.git#$X264_BRANCH /src\nCOPY build/x264.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build x265\nFROM emsdk-base AS x265-builder\nENV X265_BRANCH=3.4\nADD https://github.com/ffmpegwasm/x265.git#$X265_BRANCH /src\nCOPY build/x265.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build libvpx\nFROM emsdk-base AS libvpx-builder\nENV LIBVPX_BRANCH=v1.13.1\nADD https://github.com/ffmpegwasm/libvpx.git#$LIBVPX_BRANCH /src\nCOPY build/libvpx.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build lame\nFROM emsdk-base AS lame-builder\nENV LAME_BRANCH=master\nADD https://github.com/ffmpegwasm/lame.git#$LAME_BRANCH /src\nCOPY build/lame.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build ogg\nFROM emsdk-base AS ogg-builder\nENV OGG_BRANCH=v1.3.4\nADD https://github.com/ffmpegwasm/Ogg.git#$OGG_BRANCH /src\nCOPY build/ogg.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build theora\nFROM emsdk-base AS theora-builder\nCOPY --from=ogg-builder $INSTALL_DIR $INSTALL_DIR\nENV THEORA_BRANCH=v1.1.1\nADD https://github.com/ffmpegwasm/theora.git#$THEORA_BRANCH /src\nCOPY build/theora.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build opus\nFROM emsdk-base AS opus-builder\nENV OPUS_BRANCH=v1.3.1\nADD https://github.com/ffmpegwasm/opus.git#$OPUS_BRANCH /src\nCOPY build/opus.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build vorbis\nFROM emsdk-base AS vorbis-builder\nCOPY --from=ogg-builder $INSTALL_DIR $INSTALL_DIR\nENV VORBIS_BRANCH=v1.3.3\nADD https://github.com/ffmpegwasm/vorbis.git#$VORBIS_BRANCH /src\nCOPY build/vorbis.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build zlib\nFROM emsdk-base AS zlib-builder\nENV ZLIB_BRANCH=v1.2.11\nADD https://github.com/ffmpegwasm/zlib.git#$ZLIB_BRANCH /src\nCOPY build/zlib.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build libwebp\nFROM emsdk-base AS libwebp-builder\nCOPY --from=zlib-builder $INSTALL_DIR $INSTALL_DIR\nENV LIBWEBP_BRANCH=v1.3.2\nADD https://github.com/ffmpegwasm/libwebp.git#$LIBWEBP_BRANCH /src\nCOPY build/libwebp.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build freetype2\nFROM emsdk-base AS freetype2-builder\nENV FREETYPE2_BRANCH=VER-2-10-4\nADD https://github.com/ffmpegwasm/freetype2.git#$FREETYPE2_BRANCH /src\nCOPY build/freetype2.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build fribidi\nFROM emsdk-base AS fribidi-builder\nENV FRIBIDI_BRANCH=v1.0.9\nADD https://github.com/fribidi/fribidi.git#$FRIBIDI_BRANCH /src\nCOPY build/fribidi.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build harfbuzz\nFROM emsdk-base AS harfbuzz-builder\nENV HARFBUZZ_BRANCH=5.2.0\nADD https://github.com/harfbuzz/harfbuzz.git#$HARFBUZZ_BRANCH /src\nCOPY build/harfbuzz.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build libass\nFROM emsdk-base AS libass-builder\nCOPY --from=freetype2-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=fribidi-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=harfbuzz-builder $INSTALL_DIR $INSTALL_DIR\nENV LIBASS_BRANCH=0.15.0\nADD https://github.com/libass/libass.git#$LIBASS_BRANCH /src\nCOPY build/libass.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Build zimg\nFROM emsdk-base AS zimg-builder\nENV ZIMG_BRANCH=release-3.0.5\nRUN apt-get update && apt-get install -y git\nRUN git clone --recursive -b $ZIMG_BRANCH https://github.com/sekrit-twc/zimg.git /src\nCOPY build/zimg.sh /src/build.sh\nRUN bash -x /src/build.sh\n\n# Base ffmpeg image with dependencies and source code populated.\nFROM emsdk-base AS ffmpeg-base\nRUN embuilder build sdl2 sdl2-mt\nADD https://github.com/FFmpeg/FFmpeg.git#$FFMPEG_VERSION /src\nCOPY --from=x264-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=x265-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=libvpx-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=lame-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=opus-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=theora-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=vorbis-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=libwebp-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=libass-builder $INSTALL_DIR $INSTALL_DIR\nCOPY --from=zimg-builder $INSTALL_DIR $INSTALL_DIR\n\n# Build ffmpeg\nFROM ffmpeg-base AS ffmpeg-builder\nCOPY build/ffmpeg.sh /src/build.sh\nRUN bash -x /src/build.sh \\\n      --enable-gpl \\\n      --enable-libx264 \\\n      --enable-libx265 \\\n      --enable-libvpx \\\n      --enable-libmp3lame \\\n      --enable-libtheora \\\n      --enable-libvorbis \\\n      --enable-libopus \\\n      --enable-zlib \\\n      --enable-libwebp \\\n      --enable-libfreetype \\\n      --enable-libfribidi \\\n      --enable-libass \\\n      --enable-libzimg \n\n# Build ffmpeg.wasm\nFROM ffmpeg-builder AS ffmpeg-wasm-builder\nCOPY src/bind /src/src/bind\nCOPY src/fftools /src/src/fftools\nCOPY build/ffmpeg-wasm.sh build.sh\n# libraries to link\nENV FFMPEG_LIBS \\\n      -lx264 \\\n      -lx265 \\\n      -lvpx \\\n      -lmp3lame \\\n      -logg \\\n      -ltheora \\\n      -lvorbis \\\n      -lvorbisenc \\\n      -lvorbisfile \\\n      -lopus \\\n      -lz \\\n      -lwebpmux \\\n      -lwebp \\\n      -lsharpyuv \\\n      -lfreetype \\\n      -lfribidi \\\n      -lharfbuzz \\\n      -lass \\\n      -lzimg\nRUN mkdir -p /src/dist/umd && bash -x /src/build.sh \\\n      ${FFMPEG_LIBS} \\\n      -o dist/umd/ffmpeg-core.js\nRUN mkdir -p /src/dist/esm && bash -x /src/build.sh \\\n      ${FFMPEG_LIBS} \\\n      -sEXPORT_ES6 \\\n      -o dist/esm/ffmpeg-core.js\n\n# Export ffmpeg-core.wasm to dist/, use `docker buildx build -o . .` to get assets\nFROM scratch AS exportor\nCOPY --from=ffmpeg-wasm-builder /src/dist /dist\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Jerome Wu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "all: dev\n\nMT_FLAGS := -sUSE_PTHREADS -pthread\n\nDEV_ARGS := --progress=plain\n\nDEV_CFLAGS := --profiling\nDEV_MT_CFLAGS := $(DEV_CFLAGS) $(MT_FLAGS)\nPROD_CFLAGS := -O3 -msimd128\nPROD_MT_CFLAGS := $(PROD_CFLAGS) $(MT_FLAGS)\n\nclean:\n\trm -rf ./packages/core$(PKG_SUFFIX)/dist\n\n.PHONY: build\nbuild:\n\tmake clean PKG_SUFFIX=\"$(PKG_SUFFIX)\"\n\tEXTRA_CFLAGS=\"$(EXTRA_CFLAGS)\" \\\n\tEXTRA_LDFLAGS=\"$(EXTRA_LDFLAGS)\" \\\n\tFFMPEG_ST=\"$(FFMPEG_ST)\" \\\n\tFFMPEG_MT=\"$(FFMPEG_MT)\" \\\n\t\tdocker buildx build \\\n\t\t\t--build-arg EXTRA_CFLAGS \\\n\t\t\t--build-arg EXTRA_LDFLAGS \\\n\t\t\t--build-arg FFMPEG_MT \\\n\t\t\t--build-arg FFMPEG_ST \\\n\t\t\t-o ./packages/core$(PKG_SUFFIX) \\\n\t\t\t$(EXTRA_ARGS) \\\n\t\t\t.\n\nbuild-st:\n\tmake build \\\n\t\tFFMPEG_ST=yes\n\nbuild-mt:\n\tmake build \\\n\t\tPKG_SUFFIX=-mt \\\n\t\tFFMPEG_MT=yes\n\ndev:\n\tmake build-st EXTRA_CFLAGS=\"$(DEV_CFLAGS)\" EXTRA_ARGS=\"$(DEV_ARGS)\"\n\ndev-mt:\n\tmake build-mt EXTRA_CFLAGS=\"$(DEV_MT_CFLAGS)\" EXTRA_ARGS=\"$(DEV_ARGS)\"\n\nprd:\n\tmake build-st EXTRA_CFLAGS=\"$(PROD_CFLAGS)\"\n\nprd-mt:\n\tmake build-mt EXTRA_CFLAGS=\"$(PROD_MT_CFLAGS)\"\n"
  },
  {
    "path": "README.md",
    "content": "---\n<p align=\"center\">\n  <a href=\"#\">\n    <img alt=\"ffmpeg.wasm\" width=\"128px\" height=\"128px\" src=\"https://github.com/ffmpegwasm/ffmpeg.wasm/blob/main/apps/website/static/img/logo192.png\"></img>\n  </a>\n</p>\n\n# ffmpeg.wasm\n\nffmpeg.wasm is a pure Webassembly / Javascript port of FFmpeg. It enables video & audio record, convert and stream right inside browsers.\n\n[![stability-experimental](https://img.shields.io/badge/stability-experimental-orange.svg)](https://github.com/emersion/stability-badges#experimental)\n[![Node Version](https://img.shields.io/node/v/@ffmpeg/ffmpeg.svg)](https://img.shields.io/node/v/@ffmpeg/ffmpeg.svg)\n[![Actions Status](https://github.com/ffmpegwasm/ffmpeg.wasm/workflows/CI/badge.svg)](https://github.com/ffmpegwasm/ffmpeg.wasm/actions)\n![npm (tag)](https://img.shields.io/npm/v/@ffmpeg/ffmpeg/latest)\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/ffmpegwasm/ffmpeg.wasm/graphs/commit-activity)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Downloads Total](https://img.shields.io/npm/dt/@ffmpeg/ffmpeg.svg)](https://www.npmjs.com/package/@ffmpeg/ffmpeg)\n[![Downloads Month](https://img.shields.io/npm/dm/@ffmpeg/ffmpeg.svg)](https://www.npmjs.com/package/@ffmpeg/ffmpeg)\n[![Netlify Status](https://api.netlify.com/api/v1/badges/1943b6d3-45ad-4b46-bfba-cb8d5716604c/deploy-status)](https://app.netlify.com/sites/ffmpegwasm/deploys)\n\nJoin us on Discord!\n\n[![Discord](https://dcbadge.vercel.app/api/server/NjGMaqqfm5)](https://discord.gg/NjGMaqqfm5)\n\n## Documentation\n\n- [Introduction](https://ffmpegwasm.netlify.app/docs/overview)\n- [Getting\n    Started](https://ffmpegwasm.netlify.app/docs/getting-started/installation)\n- [API](https://ffmpegwasm.netlify.app/docs/api/ffmpeg/)\n- [FAQ](https://ffmpegwasm.netlify.app/docs/faq)\n- [Contribution](https://ffmpegwasm.netlify.app/docs/contribution/core)\n\nPlease sponsor ffmpeg.wasm to make it sustainable. :heart:\n"
  },
  {
    "path": "apps/angular-app/.editorconfig",
    "content": "# Editor configuration, see https://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.ts]\nquote_type = single\n\n[*.md]\nmax_line_length = off\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "apps/angular-app/.gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# Compiled output\n/dist\n/tmp\n/out-tsc\n/bazel-out\n\n# Node\n/node_modules\nnpm-debug.log\nyarn-error.log\n\n# IDEs and editors\n.idea/\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# Visual Studio Code\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n.history/*\n\n# Miscellaneous\n/.angular/cache\n.sass-cache/\n/connect.lock\n/coverage\n/libpeerconnection.log\ntestem.log\n/typings\n\n# System files\n.DS_Store\nThumbs.db\n"
  },
  {
    "path": "apps/angular-app/.vscode/extensions.json",
    "content": "{\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846\n  \"recommendations\": [\"angular.ng-template\"]\n}\n"
  },
  {
    "path": "apps/angular-app/.vscode/launch.json",
    "content": "{\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"ng serve\",\n      \"type\": \"chrome\",\n      \"request\": \"launch\",\n      \"preLaunchTask\": \"npm: start\",\n      \"url\": \"http://localhost:4200/\"\n    },\n    {\n      \"name\": \"ng test\",\n      \"type\": \"chrome\",\n      \"request\": \"launch\",\n      \"preLaunchTask\": \"npm: test\",\n      \"url\": \"http://localhost:9876/debug.html\"\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/angular-app/.vscode/tasks.json",
    "content": "{\n  // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558\n  \"version\": \"2.0.0\",\n  \"tasks\": [\n    {\n      \"type\": \"npm\",\n      \"script\": \"start\",\n      \"isBackground\": true,\n      \"problemMatcher\": {\n        \"owner\": \"typescript\",\n        \"pattern\": \"$tsc\",\n        \"background\": {\n          \"activeOnStart\": true,\n          \"beginsPattern\": {\n            \"regexp\": \"(.*?)\"\n          },\n          \"endsPattern\": {\n            \"regexp\": \"bundle generation complete\"\n          }\n        }\n      }\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"test\",\n      \"isBackground\": true,\n      \"problemMatcher\": {\n        \"owner\": \"typescript\",\n        \"pattern\": \"$tsc\",\n        \"background\": {\n          \"activeOnStart\": true,\n          \"beginsPattern\": {\n            \"regexp\": \"(.*?)\"\n          },\n          \"endsPattern\": {\n            \"regexp\": \"bundle generation complete\"\n          }\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/angular-app/README.md",
    "content": "# AngularApp\n\nThis project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.7.\n\n## Development server\n\nRun `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.\n\n## Code scaffolding\n\nRun `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.\n\n## Build\n\nRun `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.\n\n## Running unit tests\n\nRun `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).\n\n## Running end-to-end tests\n\nRun `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.\n\n## Further help\n\nTo get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.\n"
  },
  {
    "path": "apps/angular-app/angular.json",
    "content": "{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"angular-app\": {\n      \"projectType\": \"application\",\n      \"schematics\": {},\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"prefix\": \"app\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:application\",\n          \"options\": {\n            \"outputPath\": \"dist/angular-app\",\n            \"index\": \"src/index.html\",\n            \"browser\": \"src/main.ts\",\n            \"polyfills\": [\n              \"zone.js\"\n            ],\n            \"tsConfig\": \"tsconfig.app.json\",\n            \"assets\": [\n              \"src/favicon.ico\",\n              \"src/assets\"\n            ],\n            \"styles\": [\n              \"src/styles.css\"\n            ],\n            \"scripts\": []\n          },\n          \"configurations\": {\n            \"production\": {\n              \"budgets\": [\n                {\n                  \"type\": \"initial\",\n                  \"maximumWarning\": \"500kb\",\n                  \"maximumError\": \"1mb\"\n                },\n                {\n                  \"type\": \"anyComponentStyle\",\n                  \"maximumWarning\": \"2kb\",\n                  \"maximumError\": \"4kb\"\n                }\n              ],\n              \"outputHashing\": \"all\"\n            },\n            \"development\": {\n              \"optimization\": false,\n              \"extractLicenses\": false,\n              \"sourceMap\": true\n            }\n          },\n          \"defaultConfiguration\": \"production\"\n        },\n        \"serve\": {\n          \"builder\": \"@angular-devkit/build-angular:dev-server\",\n          \"configurations\": {\n            \"production\": {\n              \"buildTarget\": \"angular-app:build:production\"\n            },\n            \"development\": {\n              \"buildTarget\": \"angular-app:build:development\"\n            }\n          },\n          \"defaultConfiguration\": \"development\"\n        },\n        \"extract-i18n\": {\n          \"builder\": \"@angular-devkit/build-angular:extract-i18n\",\n          \"options\": {\n            \"buildTarget\": \"angular-app:build\"\n          }\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"polyfills\": [\n              \"zone.js\",\n              \"zone.js/testing\"\n            ],\n            \"tsConfig\": \"tsconfig.spec.json\",\n            \"assets\": [\n              \"src/favicon.ico\",\n              \"src/assets\"\n            ],\n            \"styles\": [\n              \"src/styles.css\"\n            ],\n            \"scripts\": []\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "apps/angular-app/package.json",
    "content": "{\n  \"name\": \"angular-app\",\n  \"version\": \"0.0.0\",\n  \"scripts\": {\n    \"ng\": \"ng\",\n    \"start\": \"ng serve\",\n    \"build\": \"ng build\",\n    \"watch\": \"ng build --watch --configuration development\",\n    \"test\": \"ng test\"\n  },\n  \"private\": true,\n  \"dependencies\": {\n    \"@angular/animations\": \"^17.0.0\",\n    \"@angular/common\": \"^17.0.0\",\n    \"@angular/compiler\": \"^17.0.0\",\n    \"@angular/core\": \"^17.0.0\",\n    \"@angular/forms\": \"^17.0.0\",\n    \"@angular/platform-browser\": \"^17.0.0\",\n    \"@angular/platform-browser-dynamic\": \"^17.0.0\",\n    \"@angular/router\": \"^17.0.0\",\n    \"@ffmpeg/ffmpeg\": \"*\",\n    \"@ffmpeg/util\": \"*\",\n    \"rxjs\": \"~7.8.0\",\n    \"tslib\": \"^2.3.0\",\n    \"zone.js\": \"~0.14.2\"\n  },\n  \"devDependencies\": {\n    \"@angular-devkit/build-angular\": \"^17.0.7\",\n    \"@angular/cli\": \"^17.0.7\",\n    \"@angular/compiler-cli\": \"^17.0.0\",\n    \"@types/jasmine\": \"~5.1.0\",\n    \"jasmine-core\": \"~5.1.0\",\n    \"karma\": \"~6.4.0\",\n    \"karma-chrome-launcher\": \"~3.2.0\",\n    \"karma-coverage\": \"~2.2.0\",\n    \"karma-jasmine\": \"~5.1.0\",\n    \"karma-jasmine-html-reporter\": \"~2.1.0\",\n    \"typescript\": \"~5.2.2\"\n  }\n}\n"
  },
  {
    "path": "apps/angular-app/src/app/app.component.css",
    "content": ""
  },
  {
    "path": "apps/angular-app/src/app/app.component.html",
    "content": "<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->\n<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->\n<!-- * * * * * * * * * * and can be replaced.  * * * * * * * * * * -->\n<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n<!-- * * * * * * * * * Delete the template below * * * * * * * * * -->\n<!-- * * * * * * * to get started with your project! * * * * * * * -->\n<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n\n<style>\n  :host {\n    --bright-blue: oklch(51.01% 0.274 263.83);\n    --electric-violet: oklch(53.18% 0.28 296.97);\n    --french-violet: oklch(47.66% 0.246 305.88);\n    --vivid-pink: oklch(69.02% 0.277 332.77);\n    --hot-red: oklch(61.42% 0.238 15.34);\n    --orange-red: oklch(63.32% 0.24 31.68);\n\n    --gray-900: oklch(19.37% 0.006 300.98);\n    --gray-700: oklch(36.98% 0.014 302.71);\n    --gray-400: oklch(70.9% 0.015 304.04);\n\n    --red-to-pink-to-purple-vertical-gradient: linear-gradient(\n      180deg,\n      var(--orange-red) 0%,\n      var(--vivid-pink) 50%,\n      var(--electric-violet) 100%\n    );\n\n    --red-to-pink-to-purple-horizontal-gradient: linear-gradient(\n      90deg,\n      var(--orange-red) 0%,\n      var(--vivid-pink) 50%,\n      var(--electric-violet) 100%\n    );\n\n    --pill-accent: var(--bright-blue);\n\n    font-family: \"Inter\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n      Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\",\n      \"Segoe UI Symbol\";\n    box-sizing: border-box;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n  }\n\n  h1 {\n    font-size: 3.125rem;\n    color: var(--gray-900);\n    font-weight: 500;\n    line-height: 100%;\n    letter-spacing: -0.125rem;\n    margin: 0;\n    font-family: \"Inter Tight\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto,\n      Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\",\n      \"Segoe UI Symbol\";\n  }\n\n  p {\n    margin: 0;\n    color: var(--gray-700);\n  }\n\n  main {\n    width: 100%;\n    min-height: 100%;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    padding: 1rem;\n    box-sizing: inherit;\n    position: relative;\n  }\n\n  @media screen and (max-width: 650px) {\n    .content {\n      flex-direction: column;\n      width: max-content;\n    }\n\n    .divider {\n      height: 1px;\n      width: 100%;\n      background: var(--red-to-pink-to-purple-horizontal-gradient);\n      margin-block: 1.5rem;\n    }\n  }\n</style>\n\n<main class=\"main\">\n  <div *ngIf=\"loaded\">\n    <video src=\"{{ videoURL }}\" controls></video>\n    <br />\n    <button (click)=\"transcode()\">Transcode avi to mp4</button>\n    <p>{{ message }}</p>\n  </div>\n  <div *ngIf=\"!loaded\">\n    <button (click)=\"load()\">Load ffmpeg-core</button>\n  </div>\n</main>\n\n<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n<!-- * * * * * * * * * * * The content above * * * * * * * * * * * * -->\n<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * * -->\n<!-- * * * * * * * * * * and can be replaced.  * * * * * * * * * * * -->\n<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n<!-- * * * * * * * * * * End of Placeholder  * * * * * * * * * * * * -->\n<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->\n\n\n<router-outlet></router-outlet>\n"
  },
  {
    "path": "apps/angular-app/src/app/app.component.spec.ts",
    "content": "import { TestBed } from '@angular/core/testing';\nimport { AppComponent } from './app.component';\n\ndescribe('AppComponent', () => {\n  beforeEach(async () => {\n    await TestBed.configureTestingModule({\n      imports: [AppComponent],\n    }).compileComponents();\n  });\n\n  it('should create the app', () => {\n    const fixture = TestBed.createComponent(AppComponent);\n    const app = fixture.componentInstance;\n    expect(app).toBeTruthy();\n  });\n\n  it(`should have the 'angular-app' title`, () => {\n    const fixture = TestBed.createComponent(AppComponent);\n    const app = fixture.componentInstance;\n    expect(app.title).toEqual('angular-app');\n  });\n\n  it('should render title', () => {\n    const fixture = TestBed.createComponent(AppComponent);\n    fixture.detectChanges();\n    const compiled = fixture.nativeElement as HTMLElement;\n    expect(compiled.querySelector('h1')?.textContent).toContain('Hello, angular-app');\n  });\n});\n"
  },
  {
    "path": "apps/angular-app/src/app/app.component.ts",
    "content": "import { Component } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RouterOutlet } from '@angular/router';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile, toBlobURL } from '@ffmpeg/util';\n\nconst baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm';\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  imports: [CommonModule, RouterOutlet],\n  templateUrl: './app.component.html',\n  styleUrl: './app.component.css',\n})\nexport class AppComponent {\n  loaded = false;\n  ffmpeg = new FFmpeg();\n  videoURL = '';\n  message = '';\n  async load() {\n    this.ffmpeg.on('log', ({ message }) => {\n      this.message = message;\n    });\n    await this.ffmpeg.load({\n      coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n      wasmURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.wasm`,\n        'application/wasm',\n      ),\n      workerURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.worker.js`,\n        'text/javascript',\n      ),\n    });\n    this.loaded = true;\n  }\n  async transcode() {\n    const videoURL =\n      'https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi';\n    await this.ffmpeg.writeFile('input.avi', await fetchFile(videoURL));\n    await this.ffmpeg.exec(['-i', 'input.avi', 'output.mp4']);\n    const fileData = await this.ffmpeg.readFile('output.mp4');\n    const data = new Uint8Array(fileData as ArrayBuffer);\n    this.videoURL = URL.createObjectURL(\n      new Blob([data.buffer], { type: 'video/mp4' }),\n    );\n  }\n}\n"
  },
  {
    "path": "apps/angular-app/src/app/app.config.ts",
    "content": "import { ApplicationConfig } from '@angular/core';\nimport { provideRouter } from '@angular/router';\n\nimport { routes } from './app.routes';\n\nexport const appConfig: ApplicationConfig = {\n  providers: [provideRouter(routes)]\n};\n"
  },
  {
    "path": "apps/angular-app/src/app/app.routes.ts",
    "content": "import { Routes } from '@angular/router';\n\nexport const routes: Routes = [];\n"
  },
  {
    "path": "apps/angular-app/src/assets/.gitkeep",
    "content": ""
  },
  {
    "path": "apps/angular-app/src/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <title>AngularApp</title>\n  <base href=\"/\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link rel=\"icon\" type=\"image/x-icon\" href=\"favicon.ico\">\n</head>\n<body>\n  <app-root></app-root>\n</body>\n</html>\n"
  },
  {
    "path": "apps/angular-app/src/main.ts",
    "content": "import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n  .catch((err) => console.error(err));\n"
  },
  {
    "path": "apps/angular-app/src/styles.css",
    "content": "/* You can add global styles to this file, and also import other style files */\n"
  },
  {
    "path": "apps/angular-app/tsconfig.app.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/app\",\n    \"types\": []\n  },\n  \"files\": [\n    \"src/main.ts\"\n  ],\n  \"include\": [\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "apps/angular-app/tsconfig.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"outDir\": \"./dist/out-tsc\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"noImplicitOverride\": true,\n    \"noPropertyAccessFromIndexSignature\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"experimentalDecorators\": true,\n    \"moduleResolution\": \"node\",\n    \"importHelpers\": true,\n    \"target\": \"ES2022\",\n    \"module\": \"ES2022\",\n    \"useDefineForClassFields\": false,\n    \"lib\": [\n      \"ES2022\",\n      \"dom\"\n    ]\n  },\n  \"angularCompilerOptions\": {\n    \"enableI18nLegacyMessageIdFormat\": false,\n    \"strictInjectionParameters\": true,\n    \"strictInputAccessModifiers\": true,\n    \"strictTemplates\": true\n  }\n}\n"
  },
  {
    "path": "apps/angular-app/tsconfig.spec.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"./out-tsc/spec\",\n    \"types\": [\n      \"jasmine\"\n    ]\n  },\n  \"include\": [\n    \"src/**/*.spec.ts\",\n    \"src/**/*.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "apps/nextjs-app/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "apps/nextjs-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n"
  },
  {
    "path": "apps/nextjs-app/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\nyarn dev\n# or\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.\n\nThis project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "apps/nextjs-app/app/Home.tsx",
    "content": "\"use client\";\n\nimport { FFmpeg } from \"@ffmpeg/ffmpeg\";\nimport { fetchFile, toBlobURL } from \"@ffmpeg/util\";\nimport { useRef, useState } from \"react\";\n\nexport default function Home() {\n  const [loaded, setLoaded] = useState(false);\n  const [isLoading, setIsLoading] = useState(false);\n  const ffmpegRef = useRef(new FFmpeg());\n  const videoRef = useRef<HTMLVideoElement | null>(null);\n  const messageRef = useRef<HTMLParagraphElement | null>(null);\n\n  const load = async () => {\n    setIsLoading(true);\n    const baseURL = \"https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd\";\n    const ffmpeg = ffmpegRef.current;\n    ffmpeg.on(\"log\", ({ message }) => {\n      if (messageRef.current) messageRef.current.innerHTML = message;\n    });\n    // toBlobURL is used to bypass CORS issue, urls with the same\n    // domain can be used directly.\n    await ffmpeg.load({\n      coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, \"text/javascript\"),\n      wasmURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.wasm`,\n        \"application/wasm\"\n      ),\n    });\n    setLoaded(true);\n    setIsLoading(false);\n  };\n\n  const transcode = async () => {\n    const ffmpeg = ffmpegRef.current;\n    // u can use 'https://ffmpegwasm.netlify.app/video/video-15s.avi' to download the video to public folder for testing\n    await ffmpeg.writeFile(\n      \"input.avi\",\n      await fetchFile(\n        \"https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi\"\n      )\n    );\n    await ffmpeg.exec([\"-i\", \"input.avi\", \"output.mp4\"]);\n    const data = (await ffmpeg.readFile(\"output.mp4\")) as any;\n    if (videoRef.current)\n      videoRef.current.src = URL.createObjectURL(\n        new Blob([data.buffer], { type: \"video/mp4\" })\n      );\n  };\n\n  return loaded ? (\n    <div className=\"fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]\">\n      <video ref={videoRef} controls></video>\n      <br />\n      <button\n        onClick={transcode}\n        className=\"bg-green-500 hover:bg-green-700 text-white py-3 px-6 rounded\"\n      >\n        Transcode avi to mp4\n      </button>\n      <p ref={messageRef}></p>\n    </div>\n  ) : (\n    <button\n      className=\"fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] flex items-center bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded\"\n      onClick={load}\n    >\n      Load ffmpeg-core\n      {isLoading && (\n        <span className=\"animate-spin ml-3\">\n          <svg\n            viewBox=\"0 0 1024 1024\"\n            focusable=\"false\"\n            data-icon=\"loading\"\n            width=\"1em\"\n            height=\"1em\"\n            fill=\"currentColor\"\n            aria-hidden=\"true\"\n          >\n            <path d=\"M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z\"></path>\n          </svg>\n        </span>\n      )}\n    </button>\n  );\n}\n"
  },
  {
    "path": "apps/nextjs-app/app/NoSSRWrapper.tsx",
    "content": "import dynamic from 'next/dynamic'\nimport React from 'react' \nconst NoSSRWrapper = props => ( \n    <React.Fragment>{props.children}</React.Fragment> \n) \nexport default dynamic(() => Promise.resolve(NoSSRWrapper), { \n    ssr: false \n})\n"
  },
  {
    "path": "apps/nextjs-app/app/globals.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n"
  },
  {
    "path": "apps/nextjs-app/app/layout.tsx",
    "content": "import './globals.css'\nimport type { Metadata } from 'next'\nimport { Inter } from 'next/font/google'\n\nconst inter = Inter({ subsets: ['latin'] })\n\nexport const metadata: Metadata = {\n  title: 'Create Next App',\n  description: 'Generated by create next app',\n}\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode\n}) {\n  return (\n    <html lang=\"en\">\n      <body className={inter.className}>{children}</body>\n    </html>\n  )\n}\n"
  },
  {
    "path": "apps/nextjs-app/app/page.tsx",
    "content": "'use client'\n\nimport NoSSRWrapper from \"./NoSSRWrapper\";\nimport Home from \"./Home\";\n\nexport default function Page() {\n  return <NoSSRWrapper><Home /></NoSSRWrapper>\n}\n"
  },
  {
    "path": "apps/nextjs-app/next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {}\n\nmodule.exports = nextConfig\n"
  },
  {
    "path": "apps/nextjs-app/package.json",
    "content": "{\n  \"name\": \"nextjs-ffmpeg-starter\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\"\n  },\n  \"dependencies\": {\n    \"@ffmpeg/ffmpeg\": \"*\",\n    \"@ffmpeg/util\": \"*\",\n    \"@types/node\": \"20.4.9\",\n    \"@types/react\": \"18.2.20\",\n    \"@types/react-dom\": \"18.2.7\",\n    \"autoprefixer\": \"10.4.14\",\n    \"eslint\": \"8.46.0\",\n    \"eslint-config-next\": \"13.4.13\",\n    \"next\": \"^14.0.4\",\n    \"postcss\": \"8.4.31\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"tailwindcss\": \"3.3.3\",\n    \"typescript\": \"5.1.6\"\n  }\n}\n"
  },
  {
    "path": "apps/nextjs-app/postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "apps/nextjs-app/tailwind.config.ts",
    "content": "import type { Config } from 'tailwindcss'\n\nconst config: Config = {\n  content: [\n    './pages/**/*.{js,ts,jsx,tsx,mdx}',\n    './components/**/*.{js,ts,jsx,tsx,mdx}',\n    './app/**/*.{js,ts,jsx,tsx,mdx}',\n  ],\n  theme: {\n    extend: {\n      backgroundImage: {\n        'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',\n        'gradient-conic':\n          'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',\n      },\n    },\n  },\n  plugins: [],\n}\nexport default config\n"
  },
  {
    "path": "apps/nextjs-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"paths\": {\n      \"@/*\": [\"./*\"]\n    }\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/react-vite-app/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  env: { browser: true, es2020: true },\n  extends: [\n    'eslint:recommended',\n    'plugin:@typescript-eslint/recommended',\n    'plugin:react-hooks/recommended',\n  ],\n  ignorePatterns: ['dist', '.eslintrc.cjs'],\n  parser: '@typescript-eslint/parser',\n  plugins: ['react-refresh'],\n  rules: {\n    'react-refresh/only-export-components': [\n      'warn',\n      { allowConstantExport: true },\n    ],\n  },\n}\n"
  },
  {
    "path": "apps/react-vite-app/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "apps/react-vite-app/README.md",
    "content": "# React + TypeScript + Vite\n\nThis template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.\n\nCurrently, two official plugins are available:\n\n- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh\n- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh\n\n## Expanding the ESLint configuration\n\nIf you are developing a production application, we recommend updating the configuration to enable type aware lint rules:\n\n- Configure the top-level `parserOptions` property like this:\n\n```js\n   parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module',\n    project: ['./tsconfig.json', './tsconfig.node.json'],\n    tsconfigRootDir: __dirname,\n   },\n```\n\n- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`\n- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`\n- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list\n"
  },
  {
    "path": "apps/react-vite-app/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vite + React + TS</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/react-vite-app/package.json",
    "content": "{\n  \"name\": \"react-vite-app\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc && vite build\",\n    \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",\n    \"preview\": \"vite preview\"\n  },\n  \"dependencies\": {\n    \"@ffmpeg/ffmpeg\": \"*\",\n    \"@ffmpeg/util\": \"*\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.2.15\",\n    \"@types/react-dom\": \"^18.2.7\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.0.0\",\n    \"@typescript-eslint/parser\": \"^6.0.0\",\n    \"@vitejs/plugin-react\": \"^4.0.3\",\n    \"eslint\": \"^8.45.0\",\n    \"eslint-plugin-react-hooks\": \"^4.6.0\",\n    \"eslint-plugin-react-refresh\": \"^0.4.3\",\n    \"typescript\": \"^5.0.2\",\n    \"vite\": \"^4.5.2\"\n  }\n}\n"
  },
  {
    "path": "apps/react-vite-app/src/App.tsx",
    "content": "import { useState, useRef } from \"react\";\nimport { FFmpeg } from \"@ffmpeg/ffmpeg\";\nimport { toBlobURL, fetchFile } from \"@ffmpeg/util\";\n\nfunction App() {\n  const [loaded, setLoaded] = useState(false);\n  const ffmpegRef = useRef(new FFmpeg());\n  const videoRef = useRef<HTMLVideoElement | null>(null);\n  const messageRef = useRef<HTMLParagraphElement | null>(null);\n\n  const load = async () => {\n    const baseURL = \"https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm\";\n    const ffmpeg = ffmpegRef.current;\n    ffmpeg.on(\"log\", ({ message }) => {\n      if (messageRef.current) messageRef.current.innerHTML = message;\n    });\n    // toBlobURL is used to bypass CORS issue, urls with the same\n    // domain can be used directly.\n    await ffmpeg.load({\n      coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, \"text/javascript\"),\n      wasmURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.wasm`,\n        \"application/wasm\"\n      ),\n      workerURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.worker.js`,\n        \"text/javascript\"\n      ),\n    });\n    setLoaded(true);\n  };\n\n  const transcode = async () => {\n    const videoURL =\n      \"https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi\";\n    const ffmpeg = ffmpegRef.current;\n    await ffmpeg.writeFile(\"input.avi\", await fetchFile(videoURL));\n    await ffmpeg.exec([\"-i\", \"input.avi\", \"output.mp4\"]);\n    const fileData = await ffmpeg.readFile(\"output.mp4\");\n    const data = new Uint8Array(fileData as ArrayBuffer);\n    if (videoRef.current) {\n      videoRef.current.src = URL.createObjectURL(\n        new Blob([data.buffer], { type: \"video/mp4\" })\n      );\n    }\n  };\n\n  return loaded ? (\n    <>\n      <video ref={videoRef} controls></video>\n      <br />\n      <button onClick={transcode}>Transcode avi to mp4</button>\n      <p ref={messageRef}></p>\n    </>\n  ) : (\n    <button onClick={load}>Load ffmpeg-core</button>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "apps/react-vite-app/src/index.css",
    "content": ":root {\n  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;\n  line-height: 1.5;\n  font-weight: 400;\n\n  color-scheme: light dark;\n  color: rgba(255, 255, 255, 0.87);\n  background-color: #242424;\n\n  font-synthesis: none;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-text-size-adjust: 100%;\n}\n\na {\n  font-weight: 500;\n  color: #646cff;\n  text-decoration: inherit;\n}\na:hover {\n  color: #535bf2;\n}\n\nbody {\n  margin: 0;\n  display: flex;\n  place-items: center;\n  min-width: 320px;\n  min-height: 100vh;\n  justify-content: center;\n}\n\nh1 {\n  font-size: 3.2em;\n  line-height: 1.1;\n}\n\nbutton {\n  border-radius: 8px;\n  border: 1px solid transparent;\n  padding: 0.6em 1.2em;\n  font-size: 1em;\n  font-weight: 500;\n  font-family: inherit;\n  background-color: #1a1a1a;\n  cursor: pointer;\n  transition: border-color 0.25s;\n}\nbutton:hover {\n  border-color: #646cff;\n}\nbutton:focus,\nbutton:focus-visible {\n  outline: 4px auto -webkit-focus-ring-color;\n}\n\n@media (prefers-color-scheme: light) {\n  :root {\n    color: #213547;\n    background-color: #ffffff;\n  }\n  a:hover {\n    color: #747bff;\n  }\n  button {\n    background-color: #f9f9f9;\n  }\n}\n"
  },
  {
    "path": "apps/react-vite-app/src/main.tsx",
    "content": "import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport App from './App.tsx'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>,\n)\n"
  },
  {
    "path": "apps/react-vite-app/src/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "apps/react-vite-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"src\"],\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }]\n}\n"
  },
  {
    "path": "apps/react-vite-app/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "apps/react-vite-app/vite.config.ts",
    "content": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n  optimizeDeps: {\n    exclude: [\"@ffmpeg/ffmpeg\", \"@ffmpeg/util\"],\n  },\n  server: {\n    headers: {\n      \"Cross-Origin-Opener-Policy\": \"same-origin\",\n      \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n    },\n  },\n});\n"
  },
  {
    "path": "apps/solidstart-app/.gitignore",
    "content": "\ndist\n.solid\n.output\n.vercel\n.netlify\n.vinxi\n\n# Environment\n.env\n.env*.local\n\n# dependencies\n/node_modules\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n*.launch\n.settings/\n\n# Temp\ngitignore\n\n# System Files\n.DS_Store\nThumbs.db\n"
  },
  {
    "path": "apps/solidstart-app/README.md",
    "content": "# SolidStart\n\nEverything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);\n\n## Creating a project\n\n```bash\n# create a new project in the current directory\nnpm init solid@latest\n\n# create a new project in my-app\nnpm init solid@latest my-app\n```\n\n## Developing\n\nOnce you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:\n\n```bash\nnpm run dev\n\n# or start the server and open the app in a new browser tab\nnpm run dev -- --open\n```\n\n## Building\n\nSolid apps are built with _presets_, which optimise your project for deployment to different environments.\n\nBy default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.\n\n## This project was created with the [Solid CLI](https://solid-cli.netlify.app)\n"
  },
  {
    "path": "apps/solidstart-app/app.config.ts",
    "content": "import { defineConfig } from \"@solidjs/start/config\";\n\nexport default defineConfig({\n    ssr: false,\n    server: {\n        static: true,\n    },\n    vite: {\n        optimizeDeps: {\n            exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util']\n        },\n    }\n});\n"
  },
  {
    "path": "apps/solidstart-app/package.json",
    "content": "{\n\t\"name\": \"solidstart-ffmpeg\",\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"dev\": \"vinxi dev\",\n\t\t\"build\": \"vinxi build\",\n\t\t\"start\": \"vinxi start\"\n\t},\n\t\"dependencies\": {\n\t\t\"@ffmpeg/ffmpeg\": \"^0.12.15\",\n\t\t\"@ffmpeg/util\": \"^0.12.2\",\n\t\t\"@solidjs/router\": \"^0.14.1\",\n\t\t\"@solidjs/start\": \"^1.0.4\",\n\t\t\"autoprefixer\": \"^10.4.19\",\n\t\t\"postcss\": \"^8.4.38\",\n\t\t\"solid-js\": \"^1.8.18\",\n\t\t\"tailwindcss\": \"^3.4.3\",\n\t\t\"vinxi\": \"^0.5.7\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=18\"\n\t}\n}\n"
  },
  {
    "path": "apps/solidstart-app/postcss.config.cjs",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "apps/solidstart-app/src/app.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n  --background-rgb: 214, 219, 220;\n  --foreground-rgb: 0, 0, 0;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --background-rgb: 0, 0, 0;\n    --foreground-rgb: 255, 255, 255;\n  }\n}\n\nbody {\n  background: rgb(var(--background-rgb));\n  color: rgb(var(--foreground-rgb));\n}\n"
  },
  {
    "path": "apps/solidstart-app/src/app.tsx",
    "content": "import { Router } from '@solidjs/router';\nimport { FileRoutes } from '@solidjs/start/router';\nimport { Suspense } from 'solid-js';\nimport './app.css';\n\nexport default function App() {\n  return (\n    <Router\n      root={(props) => (\n        <>\n          <Suspense>{props.children}</Suspense>\n        </>\n      )}>\n      <FileRoutes />\n    </Router>\n  );\n}\n"
  },
  {
    "path": "apps/solidstart-app/src/entry-client.tsx",
    "content": "// @refresh reload\nimport { mount, StartClient } from \"@solidjs/start/client\";\n\nmount(() => <StartClient />, document.getElementById(\"app\")!);\n"
  },
  {
    "path": "apps/solidstart-app/src/entry-server.tsx",
    "content": "// @refresh reload\nimport { createHandler, StartServer } from '@solidjs/start/server';\nimport { HttpHeader, HttpStatusCode } from '@solidjs/start';\n\nexport default createHandler(() => (\n  <StartServer\n    document={({ assets, children, scripts }) => (\n      <html lang='en'>\n        {/*necessary because ffmpeg library uses sharedArrayBuffer */}\n        <HttpHeader name='Cross-Origin-Opener-Policy' value='same-origin' />\n        <HttpHeader name='Cross-Origin-Embedder-Policy' value='require-corp' />\n        <head>\n          <meta charset='utf-8' />\n          <meta name='viewport' content='width=device-width, initial-scale=1' />\n          <link rel='icon' href='/favicon.ico' />\n          {assets}\n        </head>\n        <body>\n          <div id='app'>{children}</div>\n          {scripts}\n        </body>\n      </html>\n    )}\n  />\n));\n"
  },
  {
    "path": "apps/solidstart-app/src/global.d.ts",
    "content": "/// <reference types=\"@solidjs/start/env\" />\n"
  },
  {
    "path": "apps/solidstart-app/src/routes/index.tsx",
    "content": "import { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile, toBlobURL } from '@ffmpeg/util';\nimport { createSignal, Show } from 'solid-js';\n\nconst baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm';\nconst videoURL =\n  'https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi';\n\nexport default function Home() {\n  const [loaded, setLoaded] = createSignal(false);\n  const [isLoading, setIsLoading] = createSignal(false);\n  let ffmpegRef = new FFmpeg();\n  let videoRef: any = null;\n  let messageRef: any = null;\n\n  const load = async () => {\n    setIsLoading(true);\n    const ffmpeg = ffmpegRef;\n    ffmpeg.on('log', ({ message }) => {\n      if (messageRef) messageRef.innerHTML = message;\n    });\n    // toBlobURL is used to bypass CORS issue, urls with the same\n    // domain can be used directly.\n\n    await ffmpeg.load({\n      coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n      wasmURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.wasm`,\n        'application/wasm'\n      ),\n      workerURL: await toBlobURL(\n        `${baseURL}/ffmpeg-core.worker.js`,\n        'text/javascript'\n      ),\n    });\n    setLoaded(true);\n    setIsLoading(false);\n  };\n\n  const transcode = async () => {\n    const ffmpeg = ffmpegRef;\n    // u can use 'https://ffmpegwasm.netlify.app/video/video-15s.avi' to download the video to public folder for testing\n    await ffmpeg.writeFile('input.avi', await fetchFile(videoURL));\n    await ffmpeg.exec(['-i', 'input.avi', 'output.mp4']);\n    const data = (await ffmpeg.readFile('output.mp4')) as any;\n    if (videoRef)\n      videoRef.src = URL.createObjectURL(\n        new Blob([data.buffer], { type: 'video/mp4' })\n      );\n  };\n\n  return (\n    <Show\n      when={loaded()}\n      fallback={\n        <button\n          class='fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] flex items-center bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded'\n          onClick={load}>\n          Load ffmpeg-core\n          <Show when={isLoading()}>\n            <span class='animate-spin ml-3'>\n              <svg\n                viewBox='0 0 1024 1024'\n                data-icon='loading'\n                width='1em'\n                height='1em'\n                fill='currentColor'\n                aria-hidden='true'>\n                <path d='M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z'></path>\n              </svg>\n            </span>\n          </Show>\n        </button>\n      }>\n      <div class='fixed top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]'>\n        <video ref={videoRef} controls></video>\n        <br />\n        <button\n          onClick={transcode}\n          class='bg-green-500 hover:bg-green-700 text-white py-3 px-6 rounded'>\n          Transcode avi to mp4\n        </button>\n        <p ref={messageRef}></p>\n      </div>\n    </Show>\n  );\n}\n"
  },
  {
    "path": "apps/solidstart-app/tailwind.config.cjs",
    "content": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  content: [\"./src/**/*.{html,js,jsx,ts,tsx}\"],\n  theme: {\n    extend: {}\n  },\n  plugins: []\n};\n"
  },
  {
    "path": "apps/solidstart-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\",\n    \"allowJs\": true,\n    \"noEmit\": true,\n    \"strict\": true,\n    \"types\": [\"vinxi/types/client\"],\n    \"isolatedModules\": true,\n    \"paths\": {\n      \"~/*\": [\"./src/*\"]\n    }\n  }\n}\n"
  },
  {
    "path": "apps/sveltekit-app/.eslintignore",
    "content": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n.env\n.env.*\n!.env.example\n\n# Ignore files for PNPM, NPM and YARN\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\n"
  },
  {
    "path": "apps/sveltekit-app/.eslintrc.cjs",
    "content": "/** @type { import(\"eslint\").Linter.Config } */\nmodule.exports = {\n\troot: true,\n\textends: [\n\t\t'eslint:recommended',\n\t\t'plugin:@typescript-eslint/recommended',\n\t\t'plugin:svelte/recommended',\n\t\t'prettier'\n\t],\n\tparser: '@typescript-eslint/parser',\n\tplugins: ['@typescript-eslint'],\n\tparserOptions: {\n\t\tsourceType: 'module',\n\t\tecmaVersion: 2020,\n\t\textraFileExtensions: ['.svelte']\n\t},\n\tenv: {\n\t\tbrowser: true,\n\t\tes2017: true,\n\t\tnode: true\n\t},\n\toverrides: [\n\t\t{\n\t\t\tfiles: ['*.svelte'],\n\t\t\tparser: 'svelte-eslint-parser',\n\t\t\tparserOptions: {\n\t\t\t\tparser: '@typescript-eslint/parser'\n\t\t\t}\n\t\t}\n\t]\n};\n"
  },
  {
    "path": "apps/sveltekit-app/.gitignore",
    "content": ".DS_Store\nnode_modules\n/build\n/.svelte-kit\n/package\n.env\n.env.*\n!.env.example\nvite.config.js.timestamp-*\nvite.config.ts.timestamp-*\n"
  },
  {
    "path": "apps/sveltekit-app/.npmrc",
    "content": "engine-strict=true\n"
  },
  {
    "path": "apps/sveltekit-app/.prettierignore",
    "content": "# Ignore files for PNPM, NPM and YARN\npnpm-lock.yaml\npackage-lock.json\nyarn.lock\n"
  },
  {
    "path": "apps/sveltekit-app/.prettierrc",
    "content": "{\n\t\"useTabs\": true,\n\t\"singleQuote\": true,\n\t\"trailingComma\": \"none\",\n\t\"printWidth\": 100,\n\t\"plugins\": [\"prettier-plugin-svelte\"],\n\t\"overrides\": [{ \"files\": \"*.svelte\", \"options\": { \"parser\": \"svelte\" } }]\n}\n"
  },
  {
    "path": "apps/sveltekit-app/README.md",
    "content": "# create-svelte\n\nEverything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).\n\n## Creating a project\n\nIf you're seeing this, you've probably already done this step. Congrats!\n\n```bash\n# create a new project in the current directory\nnpm create svelte@latest\n\n# create a new project in my-app\nnpm create svelte@latest my-app\n```\n\n## Developing\n\nOnce you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:\n\n```bash\nnpm run dev\n\n# or start the server and open the app in a new browser tab\nnpm run dev -- --open\n```\n\n## Building\n\nTo create a production version of your app:\n\n```bash\nnpm run build\n```\n\nYou can preview the production build with `npm run preview`.\n\n> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.\n"
  },
  {
    "path": "apps/sveltekit-app/package.json",
    "content": "{\n\t\"name\": \"sveltekit-app\",\n\t\"version\": \"0.0.1\",\n\t\"private\": true,\n\t\"scripts\": {\n\t\t\"dev\": \"vite dev\",\n\t\t\"build\": \"vite build\",\n\t\t\"preview\": \"vite preview\",\n\t\t\"test\": \"npm run test:integration && npm run test:unit\",\n\t\t\"check\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json\",\n\t\t\"check:watch\": \"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch\",\n\t\t\"lint\": \"prettier --check . && eslint .\",\n\t\t\"format\": \"prettier --write .\",\n\t\t\"test:integration\": \"playwright test\",\n\t\t\"test:unit\": \"vitest\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@ffmpeg/ffmpeg\": \"*\",\n\t\t\"@ffmpeg/util\": \"*\",\n\t\t\"@playwright/test\": \"^1.41.2\",\n\t\t\"@sveltejs/adapter-auto\": \"^3.1.1\",\n\t\t\"@sveltejs/kit\": \"^2.5.0\",\n\t\t\"@sveltejs/vite-plugin-svelte\": \"^3.0.2\",\n\t\t\"@tsconfig/node18\": \"^18.2.2\",\n\t\t\"@types/eslint\": \"8.56.2\",\n\t\t\"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n\t\t\"@typescript-eslint/parser\": \"^6.21.0\",\n\t\t\"eslint\": \"^8.56.0\",\n\t\t\"eslint-config-prettier\": \"^9.1.0\",\n\t\t\"eslint-plugin-svelte\": \"^2.35.1\",\n\t\t\"prettier\": \"^3.2.5\",\n\t\t\"prettier-plugin-svelte\": \"^3.1.2\",\n\t\t\"svelte\": \"^4.2.10\",\n\t\t\"svelte-check\": \"^3.6.4\",\n\t\t\"tslib\": \"^2.6.2\",\n\t\t\"typescript\": \"^5.3.3\",\n\t\t\"vite\": \"^5.1.1\",\n\t\t\"vitest\": \"^1.2.2\"\n\t},\n\t\"type\": \"module\"\n}\n"
  },
  {
    "path": "apps/sveltekit-app/playwright.config.ts",
    "content": "import type { PlaywrightTestConfig } from '@playwright/test';\n\nconst config: PlaywrightTestConfig = {\n\twebServer: {\n\t\tcommand: 'npm run build && npm run preview',\n\t\tport: 4173\n\t},\n\ttestDir: 'tests',\n\ttestMatch: /(.+\\.)?(test|spec)\\.[jt]s/\n};\n\nexport default config;\n"
  },
  {
    "path": "apps/sveltekit-app/src/app.d.ts",
    "content": "// See https://kit.svelte.dev/docs/types#app\n// for information about these interfaces\ndeclare global {\n\tnamespace App {\n\t\t// interface Error {}\n\t\t// interface Locals {}\n\t\t// interface PageData {}\n\t\t// interface PageState {}\n\t\t// interface Platform {}\n\t}\n}\n\nexport {};\n"
  },
  {
    "path": "apps/sveltekit-app/src/app.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<link rel=\"icon\" href=\"%sveltekit.assets%/favicon.png\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t%sveltekit.head%\n\t</head>\n\t<body data-sveltekit-preload-data=\"hover\">\n\t\t<div style=\"display: contents\">%sveltekit.body%</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "apps/sveltekit-app/src/index.test.ts",
    "content": "import { describe, it, expect } from 'vitest';\n\ndescribe('sum test', () => {\n\tit('adds 1 + 2 to equal 3', () => {\n\t\texpect(1 + 2).toBe(3);\n\t});\n});\n"
  },
  {
    "path": "apps/sveltekit-app/src/lib/FFmpegDemo.svelte",
    "content": "<script lang=\"ts\">\n\timport { FFmpeg } from '@ffmpeg/ffmpeg';\n\t// @ts-ignore\n\timport type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types';\n\timport { fetchFile, toBlobURL } from '@ffmpeg/util';\n\n\tlet videoEl: HTMLVideoElement;\n\n\tconst baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm';\n\tconst videoURL = 'https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi';\n\n\tlet message = 'Click Start to Transcode';\n\n\tasync function transcode() {\n\t\tconst ffmpeg = new FFmpeg();\n\t\tmessage = 'Loading ffmpeg-core.js';\n\t\tffmpeg.on('log', ({ message: msg }: LogEvent) => {\n\t\t\tmessage = msg;\n\t\t\tconsole.log(message);\n\t\t});\n\t\tawait ffmpeg.load({\n\t\t\tcoreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n\t\t\twasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n\t\t\tworkerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript')\n\t\t});\n\t\tmessage = 'Start transcoding';\n\t\tawait ffmpeg.writeFile('test.avi', await fetchFile(videoURL));\n\t\tawait ffmpeg.exec(['-i', 'test.avi', 'test.mp4']);\n\t\tmessage = 'Complete transcoding';\n\t\tconst data = await ffmpeg.readFile('test.mp4');\n\t\tconsole.log('done');\n\t\tvideoEl.src = URL.createObjectURL(\n\t\t\tnew Blob([(data as Uint8Array).buffer], { type: 'video/mp4' })\n\t\t);\n\t}\n</script>\n\n<div>\n\t<!-- svelte-ignore a11y-media-has-caption -->\n\t<video bind:this={videoEl} controls />\n\t<br />\n\t<button on:click={transcode}>Start</button>\n\t<p>{message}</p>\n</div>\n"
  },
  {
    "path": "apps/sveltekit-app/src/lib/index.ts",
    "content": "// place files you want to import through the `$lib` alias in this folder.\n"
  },
  {
    "path": "apps/sveltekit-app/src/routes/+page.svelte",
    "content": "<script lang=\"ts\">\n\timport FFmpegDemo from '../lib/FFmpegDemo.svelte';\n</script>\n\n<h1>Welcome to SvelteKit</h1>\n<p>Visit <a href=\"https://kit.svelte.dev\">kit.svelte.dev</a> to read the documentation</p>\n<FFmpegDemo></FFmpegDemo>\n"
  },
  {
    "path": "apps/sveltekit-app/svelte.config.js",
    "content": "import adapter from '@sveltejs/adapter-auto';\nimport { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\n\n/** @type {import('@sveltejs/kit').Config} */\nconst config = {\n\t// Consult https://kit.svelte.dev/docs/integrations#preprocessors\n\t// for more information about preprocessors\n\tpreprocess: vitePreprocess(),\n\n\tkit: {\n\t\t// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.\n\t\t// If your environment is not supported or you settled on a specific environment, switch out the adapter.\n\t\t// See https://kit.svelte.dev/docs/adapters for more information about adapters.\n\t\tadapter: adapter()\n\t}\n};\n\nexport default config;\n"
  },
  {
    "path": "apps/sveltekit-app/tests/test.ts",
    "content": "import { expect, test } from '@playwright/test';\n\ntest('index page has expected h1', async ({ page }) => {\n\tawait page.goto('/');\n\tawait expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible();\n});\n"
  },
  {
    "path": "apps/sveltekit-app/tsconfig.json",
    "content": "{\n\t\"extends\": \"./.svelte-kit/tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"resolveJsonModule\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"sourceMap\": true,\n\t\t\"strict\": true,\n\t\t\"moduleResolution\": \"bundler\"\n\t}\n\t// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias\n\t//\n\t// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes\n\t// from the referenced tsconfig.json - TypeScript does not merge them in\n}\n"
  },
  {
    "path": "apps/sveltekit-app/vite.config.ts",
    "content": "import { sveltekit } from '@sveltejs/kit/vite';\nimport { fileURLToPath, URL } from 'node:url'\nimport { defineConfig } from 'vitest/config';\n\n/** @type {import('vite').Plugin} */\nconst viteServerConfig = {\n    name: 'log-request-middleware',\n    configureServer(server) {\n        server.middlewares.use((req, res, next) => {\n            res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n            res.setHeader(\"Access-Control-Allow-Methods\", \"GET\");\n            res.setHeader(\"Cross-Origin-Opener-Policy\", \"same-origin\");\n            res.setHeader(\"Cross-Origin-Embedder-Policy\", \"require-corp\");\n            next();\n        });\n    }\n};\n\n\nexport default defineConfig({\n\tplugins: [sveltekit(), viteServerConfig],\n\ttest: {\n\t\tinclude: ['src/**/*.{test,spec}.{js,ts}']\n\t},\n\tresolve: {\n\t\talias: {\n\t\t  '@': fileURLToPath(new URL('./src', import.meta.url))\n\t\t}\n\t  },\n\t  optimizeDeps: {\n\t\texclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util']\n\t  },\n\t  server: {\n\t\theaders: {\n\t\t  'Cross-Origin-Opener-Policy': 'same-origin',\n\t\t  'Cross-Origin-Embedder-Policy': 'require-corp'\n\t\t},\n\t\tfs: {\n\t\t\tallow: ['../..']\n\t\t}\n\t  }\t\n});\n"
  },
  {
    "path": "apps/vanilla-app/.gitignore",
    "content": "*.tgz\npublic/assets\n"
  },
  {
    "path": "apps/vanilla-app/README.md",
    "content": "# Vanilla / Browser Examples\n\n## Setup\n\nYou need to download assets from npm before running the examples:\n\n```bash\n$ npm run download\n```\n\n## Run\n\nTo run this example, execute:\n\n```bash\n$ npm start\n```\n\nVisit http://localhost:8080 to check available examples.\n\n## Examples\n\n| Example | Description |\n| ------- | ----------- |\n| transcode.html | Transcoding example |\n| transcode-mt.html | Transcoding example using multi-thread |\n| transcode.esm.html | Transcoding example using module |\n| trim.html | Video trimming example |\n| concatDemuxer.html | Video concat example |\n"
  },
  {
    "path": "apps/vanilla-app/package.json",
    "content": "{\n  \"name\": \"browser\",\n  \"version\": \"0.12.0-alpha.0\",\n  \"description\": \"browser example\",\n  \"private\": true,\n  \"scripts\": {\n    \"download\": \"node ../../scripts/download-assets.js\",\n    \"prestart\": \"npm run download\",\n    \"start\": \"node server.js\"\n  },\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"express\": \"^4.19.2\",\n    \"serve-index\": \"^1.9.1\",\n    \"tar\": \"^6.2.1\"\n  }\n}\n"
  },
  {
    "path": "apps/vanilla-app/public/concatDemuxer.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <script src=\"/assets/ffmpeg/package/dist/umd/ffmpeg.js\"></script>\n    <script src=\"/assets/util/package/dist/umd/index.js\"></script>\n  </head>\n\n  <body>\n    <h3>Select multiple video files to Concatenate</h3>\n    <video id=\"output-video\" controls></video><br />\n    <input type=\"file\" id=\"uploader\" multiple />\n    <p id=\"message\"></p>\n    <script>\n      const { fetchFile } = FFmpegUtil;\n      const { FFmpeg } = FFmpegWASM;\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById(\"message\");\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress, time }) => {\n\t    message.innerHTML = `${time / 1000000} s`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core/package/dist/umd/ffmpeg-core.js\",\n          });\n        }\n        message.innerHTML = \"Start Concating\";\n        const inputPaths = [];\n        for (const file of files) {\n          const { name } = file;\n          ffmpeg.writeFile(name, await fetchFile(file));\n          inputPaths.push(`file ${name}`);\n        }\n        await ffmpeg.writeFile('concat_list.txt', inputPaths.join('\\n'));\n        await ffmpeg.exec(['-f', 'concat', '-safe', '0', '-i', 'concat_list.txt', 'output.mp4']);\n        message.innerHTML = \"Complete Concating\";\n        const data = await ffmpeg.readFile('output.mp4');\n        const video = document.getElementById(\"output-video\");\n        video.src = URL.createObjectURL(\n          new Blob([data.buffer], {\n            type: \"video/mp4\"\n          })\n        );\n      };\n      const elm = document.getElementById(\"uploader\");\n      elm.addEventListener(\"change\", transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/public/style.css",
    "content": "html, body {\n  margin: 0;\n  width: 100%;\n  height: 100%\n}\nbody {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n}\n"
  },
  {
    "path": "apps/vanilla-app/public/transcode-mt.esm.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n  </head>\n  <body>\n    <h3>Upload a video to transcode to mp4 (x264) and play!</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script type=\"module\">\n      import { FFmpeg } from \"/assets/ffmpeg/package/dist/esm/index.js\";\n      import { fetchFile } from \"/assets/util/package/dist/esm/index.js\";\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress }) => {\n            message.innerHTML = `${progress * 100} %`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core-mt/package/dist/esm/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start transcoding';\n        await ffmpeg.exec(['-i', name,  'output.mp4']);\n        message.innerHTML = 'Complete transcoding';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/public/transcode-mt.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <script src=\"/assets/ffmpeg/package/dist/umd/ffmpeg.js\"></script>\n    <script src=\"/assets/util/package/dist/umd/index.js\"></script>\n  </head>\n  <body>\n    <h3>Upload a video to transcode to mp4 (x264) and play!</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script>\n      const { fetchFile } = FFmpegUtil;\n      const { FFmpeg } = FFmpegWASM;\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress, time }) => {\n            message.innerHTML = `${progress * 100} %, time: ${time / 1000000} s`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core-mt/package/dist/umd/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start transcoding';\n        console.time('exec');\n        await ffmpeg.exec(['-i', name,  'output.mp4']);\n        console.timeEnd('exec');\n        message.innerHTML = 'Complete transcoding';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/public/transcode.esm.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n  </head>\n  <body>\n    <h3>Upload a video to transcode to mp4 (x264) and play!</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script type=\"module\">\n      import { FFmpeg } from \"/assets/ffmpeg/package/dist/esm/index.js\";\n      import { fetchFile } from \"/assets/util/package/dist/esm/index.js\";\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress }) => {\n            message.innerHTML = `${progress * 100} %`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core/package/dist/esm/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start transcoding';\n        await ffmpeg.exec(['-i', name,  'output.mp4']);\n        message.innerHTML = 'Complete transcoding';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/public/transcode.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <script src=\"/assets/ffmpeg/package/dist/umd/ffmpeg.js\"></script>\n    <script src=\"/assets/util/package/dist/umd/index.js\"></script>\n  </head>\n  <body>\n    <h3>Upload a video to transcode to mp4 (x264) and play!</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script>\n      const { fetchFile } = FFmpegUtil;\n      const { FFmpeg } = FFmpegWASM;\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress, time }) => {\n            message.innerHTML = `${progress * 100} %, time: ${time / 1000000} s`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core/package/dist/umd/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start transcoding';\n        console.time('exec');\n        await ffmpeg.exec(['-i', name,  'output.mp4']);\n        console.timeEnd('exec');\n        message.innerHTML = 'Complete transcoding';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/public/trim.html",
    "content": "<html>\n  <head>\n    <link rel=\"stylesheet\" href=\"style.css\">\n    <script src=\"/assets/ffmpeg/package/dist/umd/ffmpeg.js\"></script>\n    <script src=\"/assets/util/package/dist/umd/index.js\"></script>\n  </head>\n  <body>\n    <h3>Upload a mp4 (x264) video and trim its first 1 seconds and play!</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script>\n      const { fetchFile } = FFmpegUtil;\n      const { FFmpeg } = FFmpegWASM;\n      let ffmpeg = null;\n\n      const trim = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress }) => {\n            message.innerHTML = `${progress * 100} %`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/assets/core/package/dist/umd/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start trimming';\n        await ffmpeg.exec(['-i', name, '-ss', '0', '-to', '1', 'output.mp4']);\n        message.innerHTML = 'Complete trimming';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', trim);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vanilla-app/server.js",
    "content": "const path = require(\"path\");\nconst express = require(\"express\");\nconst serveIndex = require(\"serve-index\");\nconst app = express();\nconst PORT = 8080;\nconst ROOT = path.join(__dirname, \"public\");\n\napp.use((_, res, next) => {\n  res.set({\n    \"Cross-Origin-Opener-Policy\": \"same-origin\",\n    \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n    \"Cross-Origin-Resource-Policy\": \"cross-origin\",\n    \"Origin-Agent-Cluster\": \"?1\",\n    \"Access-Control-Allow-Origin\": \"*\",\n    \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n    \"Access-Control-Allow-Headers\":\n      \"Origin, X-Requested-With, Content-Type, Accept, Range\",\n  });\n  next();\n});\n\napp.use(express.static(ROOT));\napp.use(\"/\", serveIndex(ROOT));\n\napp.listen(PORT, () => {\n  console.log(`Listening on port ${PORT}`);\n});\n"
  },
  {
    "path": "apps/vue-vite-app/.eslintrc.cjs",
    "content": "/* eslint-env node */\nrequire('@rushstack/eslint-patch/modern-module-resolution')\n\nmodule.exports = {\n  root: true,\n  'extends': [\n    'plugin:vue/vue3-essential',\n    'eslint:recommended',\n    '@vue/eslint-config-typescript',\n    '@vue/eslint-config-prettier/skip-formatting'\n  ],\n  parserOptions: {\n    ecmaVersion: 'latest'\n  }\n}\n"
  },
  {
    "path": "apps/vue-vite-app/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\n.DS_Store\ndist\ndist-ssr\ncoverage\n*.local\n\n/cypress/videos/\n/cypress/screenshots/\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "apps/vue-vite-app/.prettierrc.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/prettierrc\",\n  \"semi\": false,\n  \"tabWidth\": 2,\n  \"singleQuote\": true,\n  \"printWidth\": 100,\n  \"trailingComma\": \"none\"\n}"
  },
  {
    "path": "apps/vue-vite-app/.vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"Vue.volar\", \"Vue.vscode-typescript-vue-plugin\"]\n}\n"
  },
  {
    "path": "apps/vue-vite-app/README.md",
    "content": "# vue-vite-app\n\nThis template should help get you started developing with Vue 3 in Vite.\n\n## Recommended IDE Setup\n\n[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).\n\n## Type Support for `.vue` Imports in TS\n\nTypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.\n\nIf the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:\n\n1. Disable the built-in TypeScript Extension\n    1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette\n    2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`\n2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.\n\n## Customize configuration\n\nSee [Vite Configuration Reference](https://vitejs.dev/config/).\n\n## Project Setup\n\n```sh\nnpm install\n```\n\n### Compile and Hot-Reload for Development\n\n```sh\nnpm run dev\n```\n\n### Type-Check, Compile and Minify for Production\n\n```sh\nnpm run build\n```\n\n### Lint with [ESLint](https://eslint.org/)\n\n```sh\nnpm run lint\n```\n"
  },
  {
    "path": "apps/vue-vite-app/env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "apps/vue-vite-app/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <link rel=\"icon\" href=\"/favicon.ico\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Vite App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "apps/vue-vite-app/package.json",
    "content": "{\n  \"name\": \"vue-vite-app\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"run-p type-check build-only\",\n    \"preview\": \"vite preview\",\n    \"build-only\": \"vite build\",\n    \"type-check\": \"vue-tsc --noEmit -p tsconfig.app.json --composite false\",\n    \"lint\": \"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore\",\n    \"format\": \"prettier --write src/\"\n  },\n  \"dependencies\": {\n    \"@ffmpeg/ffmpeg\": \"*\",\n    \"@ffmpeg/util\": \"*\",\n    \"vue\": \"^3.4.18\"\n  },\n  \"devDependencies\": {\n    \"@rushstack/eslint-patch\": \"^1.7.2\",\n    \"@tsconfig/node18\": \"^18.2.2\",\n    \"@types/node\": \"^20.11.17\",\n    \"@vitejs/plugin-vue\": \"^5.0.4\",\n    \"@vitejs/plugin-vue-jsx\": \"^3.1.0\",\n    \"@vue/eslint-config-prettier\": \"^9.0.0\",\n    \"@vue/eslint-config-typescript\": \"^12.0.0\",\n    \"@vue/tsconfig\": \"^0.5.1\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-vue\": \"^9.21.1\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"prettier\": \"^3.2.5\",\n    \"typescript\": \"~5.3.3\",\n    \"vite\": \"^4.5.2\",\n    \"vue-tsc\": \"^1.8.27\"\n  }\n}\n"
  },
  {
    "path": "apps/vue-vite-app/src/App.vue",
    "content": "<script setup lang=\"ts\">\nimport FFmpegDemo from './components/FFmpegDemo.vue'\n</script>\n\n<template>\n  <main>\n    <FFmpegDemo />\n  </main>\n</template>\n"
  },
  {
    "path": "apps/vue-vite-app/src/assets/base.css",
    "content": "/* color palette from <https://github.com/vuejs/theme> */\n:root {\n  --vt-c-white: #ffffff;\n  --vt-c-white-soft: #f8f8f8;\n  --vt-c-white-mute: #f2f2f2;\n\n  --vt-c-black: #181818;\n  --vt-c-black-soft: #222222;\n  --vt-c-black-mute: #282828;\n\n  --vt-c-indigo: #2c3e50;\n\n  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);\n  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);\n  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);\n  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);\n\n  --vt-c-text-light-1: var(--vt-c-indigo);\n  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);\n  --vt-c-text-dark-1: var(--vt-c-white);\n  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);\n}\n\n/* semantic color variables for this project */\n:root {\n  --color-background: var(--vt-c-white);\n  --color-background-soft: var(--vt-c-white-soft);\n  --color-background-mute: var(--vt-c-white-mute);\n\n  --color-border: var(--vt-c-divider-light-2);\n  --color-border-hover: var(--vt-c-divider-light-1);\n\n  --color-heading: var(--vt-c-text-light-1);\n  --color-text: var(--vt-c-text-light-1);\n\n  --section-gap: 160px;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --color-background: var(--vt-c-black);\n    --color-background-soft: var(--vt-c-black-soft);\n    --color-background-mute: var(--vt-c-black-mute);\n\n    --color-border: var(--vt-c-divider-dark-2);\n    --color-border-hover: var(--vt-c-divider-dark-1);\n\n    --color-heading: var(--vt-c-text-dark-1);\n    --color-text: var(--vt-c-text-dark-2);\n  }\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n  margin: 0;\n  font-weight: normal;\n}\n\nbody {\n  min-height: 100vh;\n  color: var(--color-text);\n  background: var(--color-background);\n  transition:\n    color 0.5s,\n    background-color 0.5s;\n  line-height: 1.6;\n  font-family:\n    Inter,\n    -apple-system,\n    BlinkMacSystemFont,\n    'Segoe UI',\n    Roboto,\n    Oxygen,\n    Ubuntu,\n    Cantarell,\n    'Fira Sans',\n    'Droid Sans',\n    'Helvetica Neue',\n    sans-serif;\n  font-size: 15px;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n"
  },
  {
    "path": "apps/vue-vite-app/src/assets/main.css",
    "content": "@import './base.css';\n\n#app {\n  max-width: 1280px;\n  margin: 0 auto;\n  padding: 2rem;\n\n  font-weight: normal;\n}\n\na,\n.green {\n  text-decoration: none;\n  color: hsla(160, 100%, 37%, 1);\n  transition: 0.4s;\n}\n\n@media (hover: hover) {\n  a:hover {\n    background-color: hsla(160, 100%, 37%, 0.2);\n  }\n}\n\n@media (min-width: 1024px) {\n  body {\n    display: flex;\n    place-items: center;\n  }\n\n  #app {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    padding: 0 2rem;\n  }\n}\n"
  },
  {
    "path": "apps/vue-vite-app/src/components/FFmpegDemo.vue",
    "content": "<template>\n  <video :src=\"video\" controls />\n  <br />\n  <button @click=\"transcode\">Start</button>\n  <p>{{ message }}</p>\n</template>\n\n<script lang=\"ts\">\nimport { FFmpeg } from '@ffmpeg/ffmpeg'\nimport type { LogEvent } from '@ffmpeg/ffmpeg/dist/esm/types'\nimport { fetchFile, toBlobURL } from '@ffmpeg/util'\nimport { defineComponent, ref } from 'vue'\n\nconst baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm'\nconst videoURL = 'https://raw.githubusercontent.com/ffmpegwasm/testdata/master/video-15s.avi'\n\nexport default defineComponent({\n  name: 'App',\n  setup() {\n    const ffmpeg = new FFmpeg()\n    const message = ref('Click Start to Transcode')\n    let video = ref('')\n\n    async function transcode() {\n      message.value = 'Loading ffmpeg-core.js'\n      ffmpeg.on('log', ({ message: msg }: LogEvent) => {\n        message.value = msg\n      })\n      await ffmpeg.load({\n        coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n        wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript')\n      })\n      message.value = 'Start transcoding'\n      await ffmpeg.writeFile('test.avi', await fetchFile(videoURL))\n      await ffmpeg.exec(['-i', 'test.avi', 'test.mp4'])\n      message.value = 'Complete transcoding'\n      const data = await ffmpeg.readFile('test.mp4')\n      video.value = URL.createObjectURL(\n        new Blob([(data as Uint8Array).buffer], { type: 'video/mp4' })\n      )\n    }\n    return {\n      video,\n      message,\n      transcode\n    }\n  }\n})\n</script>\n\n<style>\n#app {\n  font-family: Avenir, Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  margin-top: 60px;\n}\n</style>\n"
  },
  {
    "path": "apps/vue-vite-app/src/main.ts",
    "content": "import './assets/main.css'\n\nimport { createApp } from 'vue'\nimport App from './App.vue'\n\ncreateApp(App).mount('#app')\n"
  },
  {
    "path": "apps/vue-vite-app/tsconfig.app.json",
    "content": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.dom.json\",\n  \"include\": [\"env.d.ts\", \"src/**/*\", \"src/**/*.vue\"],\n  \"exclude\": [\"src/**/__tests__/*\"],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    },\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"node\"\n  }\n}\n"
  },
  {
    "path": "apps/vue-vite-app/tsconfig.json",
    "content": "{\n  \"files\": [],\n  \"references\": [\n    {\n      \"path\": \"./tsconfig.node.json\"\n    },\n    {\n      \"path\": \"./tsconfig.app.json\"\n    }\n  ]\n}\n"
  },
  {
    "path": "apps/vue-vite-app/tsconfig.node.json",
    "content": "{\n  \"extends\": \"@tsconfig/node18/tsconfig.json\",\n  \"include\": [\n    \"vite.config.*\",\n    \"vitest.config.*\",\n    \"cypress.config.*\",\n    \"nightwatch.conf.*\",\n    \"playwright.config.*\"\n  ],\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"types\": [\"node\"]\n  }\n}\n"
  },
  {
    "path": "apps/vue-vite-app/vite.config.ts",
    "content": "import { fileURLToPath, URL } from 'node:url'\n\nimport { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport vueJsx from '@vitejs/plugin-vue-jsx'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [vue(), vueJsx()],\n  resolve: {\n    alias: {\n      '@': fileURLToPath(new URL('./src', import.meta.url))\n    }\n  },\n  optimizeDeps: {\n    exclude: ['@ffmpeg/ffmpeg', '@ffmpeg/util']\n  },\n  server: {\n    headers: {\n      'Cross-Origin-Opener-Policy': 'same-origin',\n      'Cross-Origin-Embedder-Policy': 'require-corp'\n    }\n  }\n})\n"
  },
  {
    "path": "apps/website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n/docs/api\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "apps/website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.\n\n### Installation\n\nWhen cloning the repository, make sure you have git-lfs installed. If you install git-lfs after cloning, simple run\n`git lfs pull` to download large files.\n\n```\n$ npm install\n```\n\n### Local Development\n\n```\n$ npm start\n```\n\nThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.\n\n### Build\n\n```\n$ npm run build\n```\n\nThis command generates static content into the `build` directory and can be served using any static contents hosting service.\n\n### Deployment\n\nUsing SSH:\n\n```\n$ USE_SSH=true npm run deploy\n```\n\nNot using SSH:\n\n```\n$ GIT_USER=<Your GitHub username> npm run deploy\n```\n\nIf you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.\n"
  },
  {
    "path": "apps/website/assets/ffmpegwasm-arch.drawio",
    "content": "<mxfile host=\"Electron\" modified=\"2023-07-25T14:12:19.793Z\" agent=\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/112.0.5615.204 Electron/24.6.1 Safari/537.36\" etag=\"yk2PXCvCPGaUw3GiHUln\" version=\"21.6.1\" type=\"device\">\n  <diagram name=\"Page-1\" id=\"EXaSSQoJnIOsS1fF1PBt\">\n    <mxGraphModel dx=\"1114\" dy=\"829\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"1169\" pageHeight=\"827\" math=\"0\" shadow=\"0\">\n      <root>\n        <mxCell id=\"0\" />\n        <mxCell id=\"1\" parent=\"0\" />\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-27\" value=\"if core is multithread version\" style=\"rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;dashed=1;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"720\" y=\"110\" width=\"220\" height=\"420\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-7\" value=\"Sends Message\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-1\" target=\"veUAN4s3yOlf8Hxa7Fyb-3\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-1\" value=\"ffmpeg&lt;br style=&quot;font-size: 14px;&quot;&gt;(JavaScript)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;verticalAlign=top;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"130\" y=\"110\" width=\"120\" height=\"420\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-2\" value=\"Main Thread\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"145\" y=\"50\" width=\"90\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-8\" value=\"Sends Message\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=1;entryY=0.75;entryDx=0;entryDy=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-3\" target=\"veUAN4s3yOlf8Hxa7Fyb-1\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-3\" value=\"ffmpeg.worker&lt;br style=&quot;font-size: 14px;&quot;&gt;(JavaScript)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;verticalAlign=top;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"450\" y=\"110\" width=\"150\" height=\"420\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-4\" value=\"Web Worker&lt;br style=&quot;font-size: 14px;&quot;&gt;(Worker Thread)\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"465\" y=\"50\" width=\"120\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-5\" value=\"load()\" style=\"rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"140\" y=\"210\" width=\"100\" height=\"50\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-6\" value=\"exec()\" style=\"rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"140\" y=\"280\" width=\"100\" height=\"50\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-22\" value=\"Spawns\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-9\" target=\"veUAN4s3yOlf8Hxa7Fyb-20\">\n          <mxGeometry x=\"0.0087\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-23\" value=\"Spawns\" style=\"rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-9\" target=\"veUAN4s3yOlf8Hxa7Fyb-15\">\n          <mxGeometry x=\"0.0025\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-24\" value=\"Spawns\" style=\"rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-9\" target=\"veUAN4s3yOlf8Hxa7Fyb-21\">\n          <mxGeometry relative=\"1\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-9\" value=\"ffmpeg-core&lt;br style=&quot;font-size: 14px;&quot;&gt;(WebAssembly)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;verticalAlign=top;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"465\" y=\"210\" width=\"120\" height=\"230\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-10\" value=\"File System\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"475\" y=\"378\" width=\"100\" height=\"46\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-25\" value=\"\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" edge=\"1\" parent=\"1\" source=\"veUAN4s3yOlf8Hxa7Fyb-11\" target=\"veUAN4s3yOlf8Hxa7Fyb-10\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-11\" value=\"exec()\" style=\"rounded=0;whiteSpace=wrap;html=1;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"475\" y=\"260\" width=\"100\" height=\"50\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-15\" value=\"ffmpeg-core.worker&lt;br style=&quot;font-size: 14px;&quot;&gt;(JavaScript)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;verticalAlign=middle;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"755\" y=\"160\" width=\"150\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-20\" value=\"ffmpeg-core.worker&lt;br style=&quot;font-size: 14px;&quot;&gt;(JavaScript)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;verticalAlign=middle;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"755\" y=\"290\" width=\"150\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-21\" value=\"ffmpeg-core.worker&lt;br style=&quot;font-size: 14px;&quot;&gt;(JavaScript)\" style=\"rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;verticalAlign=middle;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"755\" y=\"410\" width=\"150\" height=\"70\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"veUAN4s3yOlf8Hxa7Fyb-26\" value=\"File I/O\" style=\"text;html=1;strokeColor=none;fillColor=#e1d5e7;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontFamily=Noto Sans;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DNoto%2BSans;\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"495\" y=\"330\" width=\"60\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n      </root>\n    </mxGraphModel>\n  </diagram>\n</mxfile>\n"
  },
  {
    "path": "apps/website/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "apps/website/blog/2023-07-26-release-ffmpeg.wasm-0.12.0.mdx",
    "content": "---\nslug: release-ffmpeg.wasm-0.12.0\ntitle: Release ffmpeg.wasm 0.12.0\nauthors: [jeromewu]\ntags: [ffmpeg.wasm]\n---\n\nFinally, a new start. :tada:\n\n<!--truncate-->\n\nI started to work on ffmpeg.wasm around Oct. 2019, it was the time\nWebAssembly is still in very early stage and transpiling FFmpeg to ffmpeg.wasm\nwas very challenging. (but possible as there was a pioneer project\n[ffmpeg.js](https://github.com/Kagami/ffmpeg.js/)) Over these years, I\nhave been trying to make ffmpeg.wasm to be production-grade, but failed\nas FFmpeg is such a powerful framework and WebAssembly is still evolving.\nIt wasn't easy to support even one requirements (ex. RTSP) from the community\nand I found it really hard to continue sometimes. But with almost **11k stars**,\n**600 forks**, **4.1k used-by projects** and **2.3M downloads** in total,\nI still believe ffmpeg.wasm is a meaningful project to continue.\nThat's why I decided to pause a little while and rethink what\nshould be done in the next stage.\n\nAs the result, I started to work on ffmpeg.wasm 0.12.0, it is a major version and\nnot backward compatible with 0.11.0. Massive issues are fixed in this version,\nincluding:\n\n- Upgrade Emscripten to 3.1.40\n- Upgrade FFmpeg to n5.1.3\n- Docker build with cache (reduce time to build a new version)\n- Support timeout(), terminate() and other fundamental operations\n- Split libraries to multiple small libraries\n- Rewrite the whole library with TypeScript\n- Merge multiple repositories into one monorepo\n- Offical Web Worker support\n- Offical single thread and multi thread version support\n- Enhanced documentation\n- Official domain name\n\nLots of features are still in the backlog and it requires lots effort to\neven just compelete one of them, such as:\n\n- Speed up ffmpeg.wasm using WebAssembly intrinsic\n- Support RTSP protocol\n- Support more popular libraries\n\nI believe there is still a long way to go for ffmpeg.wasm to really become\na production-grade library, but it is defintely a gamechanger and a chance\nto see the potential of WebAssembly and web technologies in general. That's\nwhy I am working on it and welcome to join us.\n\nHope you enjoy this release :smile:\n\n\\- Jerome\n"
  },
  {
    "path": "apps/website/blog/authors.yml",
    "content": "jeromewu:\n  name: Jerome Wu\n  title: Maintainer of ffmpeg.wasm\n  url: https://github.com/jeromewu\n  image_url: /img/jeromewu.png\n"
  },
  {
    "path": "apps/website/deploy.sh",
    "content": "#!/bin/bash\n\nnpm install\nnpm run build\n"
  },
  {
    "path": "apps/website/docs/contribution/core.md",
    "content": "# @ffmpeg/core\n\nTo build @ffmpeg/core, make sure your docker is version 23.0+ as\n[buildx](https://docs.docker.com/build/architecture/) is adopted. Also\nYou will need to install `make` to run build scripts.\n\n## Build\n\nDev Build (single thread):\n```bash\n$ make dev\n```\n\nDev Build (multithread):\n```bash\n$ make dev-mt\n```\n\nProdution Build (single thread):\n```bash\n$ make prd\n```\n\nProdution Build (multithread):\n```bash\n$ make prd-mt\n```\n\n> Each build might take around 1 hour depends on the spec of your machine,\n> subsequent builds are faster as most layers are cached.\n\nThe output file locates at **/packages/core** or **/packages/core-mt**.\n\n## Custom Build / Reduce Build Size\n\nYou can customize your build to include only the libraries you need, which can significantly reduce the final build size. This is done by modifying the `Dockerfile`.\n\n---\n\n### Step-by-Step Example: Removing WebP Support\n\nHere's how to remove `libwebp` (WebP image support) from the build. The same principle applies to other libraries.\n\nYou need to make changes in **4 places** in the `Dockerfile`:\n\n#### 1. Remove the library builder stage\n\nFind the stage that builds the library you want to remove and delete the entire block:\n\n```dockerfile\n# Remove this entire block\nFROM emsdk-base AS libwebp-builder\nCOPY --from=zlib-builder $INSTALL_DIR $INSTALL_DIR\nENV LIBWEBP_BRANCH=v1.3.2\nADD https://github.com/ffmpegwasm/libwebp.git#$LIBWEBP_BRANCH /src\nCOPY build/libwebp.sh /src/build.sh\nRUN bash -x /src/build.sh\n```\n\n#### 2. Remove the COPY instruction\n\nIn the `ffmpeg-base` stage, remove the line that copies the built library:\n\n```dockerfile\n# Remove this line\nCOPY --from=libwebp-builder $INSTALL_DIR $INSTALL_DIR\n```\n\n#### 3. Remove the configure flag\n\nIn the `ffmpeg-builder` stage, remove the corresponding `--enable-lib...` flag:\n\n```dockerfile\n# Remove this line from the ffmpeg-builder stage\n--enable-libwebp \\\n```\n\n#### 4. Remove the linker flags\n\nIn the `ffmpeg-wasm-builder` stage, remove the library from `FFMPEG_LIBS`:\n\n```dockerfile\n# Remove these lines from FFMPEG_LIBS\n-lwebpmux \\\n-lwebp \\\n-lsharpyuv \\\n```\n\n> **💡 Pro Tip:** Start by removing just the main library flag (e.g., `-lwebp`). If the build fails with \"undefined reference\" errors, those errors will tell you exactly which additional libraries to remove.\n\n#### 5. Build and test\n\n```bash\n# Run the build command\nmake prd\n\n# Output will be in packages/core/dist/\n```\n---\n\n**Additional Build Size Optimization:**\n\nYou can sometimes play around with `build/ffmpeg-wasm.sh` and `build/ffmpeg.sh` to disable things you are not using to make the size smaller.\n\n### More Advance Customization Example: Creating a Minimal Build\n\nFor more advanced customization, you might want to create a minimal build that only includes the features you need. A good example is creating a build that can create a video from a sequence of images (e.g., from an HTML canvas), handle MP4 encoding/decoding, and support audio.\n\nA community member, @Kaizodo, shared an approach that resulted in a build size of only 4.80MB. You can find the full details and a discussion in [GitHub Issue #866](https://github.com/ffmpegwasm/ffmpeg.wasm/issues/866).\n\nThe general strategy is to:\n\n1.  **Start with a minimal configuration:** Instead of removing libraries one by one, a more effective approach is to start with a minimal ffmpeg configuration. This can be achieved by using flags like `--disable-everything` in the ffmpeg configuration step within the `Dockerfile`.\n2.  **Enable specific components:** After disabling everything, you can selectively enable only the encoders, decoders, muxers, demuxers, and protocols you need for your specific use case. For example: `--enable-encoder=libx264`, `--enable-decoder=png`, `--enable-muxer=mp4`, etc.\n3.  **Include only necessary libraries:** Make sure your `Dockerfile` only builds and links the external libraries that correspond to the features you enabled (e.g., `libx264`). You can remove the build stages for any other libraries.\n\nThis approach gives you control over the build content and its final size.\n\nWe would like to thank @Kaizodo, @harkdawg and other community members for sharing their knowledge!\n## Publish\n\nSimply run `npm publish` under **packages/core** or **/packages/core-mt**.\n"
  },
  {
    "path": "apps/website/docs/contribution/ffmpeg.md",
    "content": "# @ffmpeg/ffmpeg\n\nThe source code of @ffmpeg/ffmpeg locates at **/packages/ffmpeg**.\n\n## Development\n\n```bash\n$ npm run dev\n```\n\n## Build\n\nTranspile Typescript to JavaScript.\n\n```bash\n$ npm run build\n```\n\n## Lint\n\n```bash\n$ npm run lint\n```\n\n## Publish\n\nSimply run `npm publish` under **packages/ffmpeg**.\n"
  },
  {
    "path": "apps/website/docs/contribution/util.md",
    "content": "# @ffmpeg/util\n\nThe source code of @ffmpeg/util locates at **/packages/util**.\n\n## Development\n\n```bash\n$ npm run dev\n```\n\n## Build\n\nTranspile Typescript to JavaScript.\n\n```bash\n$ npm run build\n```\n\n## Lint\n\n```bash\n$ npm run lint\n```\n\n## Publish\n\nSimply run `npm publish` under **packages/util**.\n"
  },
  {
    "path": "apps/website/docs/faq.md",
    "content": "# FAQ\n\n### Why ffmpeg.wasm doesn't support nodejs?\n\nffmpeg.wasm did support nodejs before 0.12.0, but decided to discontinue nodejs support due to:\n\n- It takes extra effort to maintain nodejs support\n- If you are not in browser, there are a lot of better choices than using WebAssembly for a better performance, ex:\n  - nodejs: https://www.npmjs.com/package/fluent-ffmpeg\n  - react-native: https://github.com/arthenica/ffmpeg-kit\n\nOf course, it is still highly welcome to contribute a nodejs version of ffmpeg.wasm.\n\n### Why ffmpeg.wasm is so slow comparing to ffmpeg?\n\nAs of now, WebAssembly is still a lot slower than native, it is possible to further speed up using\nWebAssembly intrinsic, which is basically writing assembly code. It is something we are investigating\nand hope to introduce in the future.\n\nIf you are OK with more unstable version of ffmpeg.wasm, using ffmpeg.wasm multithread (mt) version\ncan have around 2x speed comparing to single thread (but consume a lot more memory and cpu)\n\n### Is RTSP supported by ffmpeg.wasm?\n\nWe are trying to support, but so far WebAssembly itself lack of features like sockets which makes\nit hard to implement RTSP protocol. Possible workarounds are still under investigation.\n\n### What is the license of ffmpeg.wasm?\n\nThere are two components inside ffmpeg.wasm:\n\n- @ffmpeg/ffmpeg (https://github.com/ffmpegwasm/ffmpeg.wasm/packages/ffmpeg)\n- @ffmpeg/core (https://github.com/ffmpegwasm/ffmpeg.wasm/packages/core)\n\n@ffmpeg/core contains WebAssembly code which is transpiled from original FFmpeg C code with minor modifications, but overall it still following the same licenses as FFmpeg and its external libraries (as each external libraries might have its own license).\n\n@ffmpeg/ffmpeg contains kind of a wrapper to handle the complexity of loading core and calling low-level APIs. It is a small code base and under MIT license.\n\n### What is the maximum size of input file?\n\n2 GB, which is a hard limit in WebAssembly. Might become 4 GB in the future.\n\n### How can I build my own ffmpeg.wasm?\n\nIn fact, it is `@ffmpeg/core` most people would like to build.\n\nTo build on your own, you can check [Contribution Guide](/docs/contribution/core)\n\nAlso you can check this series of posts to learn more fundamental concepts\n(OUTDATED, but still good to learn foundations):\n\n- https://jeromewu.github.io/build-ffmpeg-webassembly-version-part-1-preparation/\n- https://jeromewu.github.io/build-ffmpeg-webassembly-version-part-2-compile-with-emscripten/\n- https://jeromewu.github.io/build-ffmpeg-webassembly-version-part-3-v0.1/\n- https://jeromewu.github.io/build-ffmpeg-webassembly-version-part-4-v0.2/\n"
  },
  {
    "path": "apps/website/docs/getting-started/examples.md",
    "content": "import Grid from '@mui/material/Unstable_Grid2';\nimport MuiThemeProvider from \"@site/src/components/common/MuiThemeProvider\";\nimport ExampleCard from \"@site/src/components/common/ExampleCard\";\n\n# Examples\n\nYou can find how to use ffmpeg.wasm with frameworks here. :smile:\n\n:::caution\nDo remember to run `npm run build` in the root of the repository before trying\nany of the examples.\n:::\n\n<MuiThemeProvider>\n  <Grid container rowSpacing={1} columnSpacing={1}>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/vanilla.png\"\n        title=\"Vanilla JavaScript\"\n        desc=\"Plain JavaScript\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/vanilla-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/react-vite.png\"\n        title=\"React + Vite\"\n        desc=\"React with Vite (multithread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/react-vite-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/vue-vite.png\"\n        title=\"Vue + Vite\"\n        desc=\"Vue with Vite (multithread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/vue-vite-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/angular.png\"\n        title=\"Angular\"\n        desc=\"Angular (multithread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/angular-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/nextjs.png\"\n        title=\"Next.js\"\n        desc=\"Next.js (single thread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/nextjs-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/sveltekit-vite.png\"\n        title=\"SvelteKit + Vite\"\n        desc=\"SvelteKit with Vite (multithread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/sveltekit-app\"\n      />\n    </Grid>\n    <Grid xs={12} sm={6} md={6} lg={6} xl={4}>\n      <ExampleCard\n        img=\"/img/solidstart-vite.png\"\n        title=\"SolidStart + Vite\"\n        desc=\"SolidStart with Vite (multithread version)\"\n        url=\"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/solidstart-app\"\n      />\n    </Grid>\n  </Grid>\n</MuiThemeProvider>\n"
  },
  {
    "path": "apps/website/docs/getting-started/installation.md",
    "content": "import Tabs from '@theme/Tabs';\nimport TabItem from '@theme/TabItem';\n\n# Installation\n\n:::note\nffmpeg.wasm only supports running in browser, see [FAQ](/docs/faq) for more\ndetails\n:::\n\n## Package Managers\n\nInstall ffmpeg.wasm using package managers like npm and yarn:\n\n<Tabs>\n<TabItem value=\"npm\" label=\"npm\" default>\n\n```bash\nnpm install @ffmpeg/ffmpeg @ffmpeg/util\n```\n\n</TabItem>\n<TabItem value=\"yarn\" label=\"yarn\">\n\n```bash\nyarn add @ffmpeg/ffmpeg @ffmpeg/util\n```\n\n</TabItem>\n</Tabs>\n\n:::info\nAs `@ffmpeg/ffmpeg` spawns a web worker, you cannot import `@ffmpeg/ffmpeg` from CDN like\njsdelivr. It is recommended to download it and host it on your server most of the time.\n:::\n"
  },
  {
    "path": "apps/website/docs/getting-started/usage.md",
    "content": "# Usage\n\nLearn the basics of using ffmpeg.wasm.\n\n:::note\nIt is recommended to read [Overview](/docs/overview) first.\n:::\n\n## Transcode webm to mp4 video\n\n:::caution\nIf you are a [vite](https://vitejs.dev/) user, use `esm` in **baseURL** instead of `umd`:\n\n~~https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd~~ => https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm\n:::\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile, toBlobURL } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Transcode webm to mp4</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Transcode webm to mp4 video (multi-thread)\n\n:::caution\nAs SharedArrayBuffer is required for multithread version, make sure\nyou have have fulfilled [Security Requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements).\n:::\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile, toBlobURL } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n            workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Transcode webm to mp4</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Transcode video with timeout\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        // The exec should stop after 1 second.\n        await ffmpeg.exec(['-i', 'input.webm', 'output.mp4'], 1000);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Transcode webm to mp4</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Transcode video with progress (experimental)\n\n:::danger\n`progress` is an experimental feature and might not work for many cases\n(ex. concat video files, convert image files, ...). Please use with caution.\n:::\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        // Listen to progress event instead of log.\n        ffmpeg.on('progress', ({ progress, time }) => {\n            messageRef.current.innerHTML = `${progress * 100} % (transcoded time: ${time / 1000000} s)`;\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Transcode webm to mp4</button>\n                <p ref={messageRef}></p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Split video into segments of equal duration\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.exec([\n            '-i',\n            'input.webm',\n            '-f',\n            'segment',\n            '-segment_time',\n            '3',\n            '-g',\n            '9',\n            '-sc_threshold',\n            '0',\n            '-force_key_frames',\n            'expr:gte(t,n_forced*9)',\n            '-reset_timestamps',\n            '1',\n            '-map',\n            '0',\n            'output_%d.mp4'\n        ]);\n        const data = await ffmpeg.readFile('output_1.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Split video to segments of 3 sec. and plays 2nd segment</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Display Text on the video\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.writeFile('arial.ttf', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/arial.ttf'));\n        await ffmpeg.exec([\n            '-i',\n            'input.webm',\n            '-vf',\n            'drawtext=fontfile=/arial.ttf:text=\\'ffmpeg.wasm\\':x=10:y=10:fontsize=24:fontcolor=white',\n            'output.mp4',\n        ]);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Transcode webm to mp4 with text</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Interlace 2 Videos\n\n```jsx live\n// import { FFmpeg } from '@ffmpeg/ffmpeg';\n// import { fetchFile } from '@ffmpeg/util';\nfunction() {\n    const [loaded, setLoaded] = useState(false);\n    const ffmpegRef = useRef(new FFmpeg());\n    const videoRef = useRef(null);\n    const messageRef = useRef(null);\n\n    const load = async () => {\n        const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/umd'\n        const ffmpeg = ffmpegRef.current;\n        ffmpeg.on('log', ({ message }) => {\n            messageRef.current.innerHTML = message;\n            console.log(message);\n        });\n        // toBlobURL is used to bypass CORS issue, urls with the same\n        // domain can be used directly.\n        await ffmpeg.load({\n            coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n            wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n        });\n        setLoaded(true);\n    }\n\n    const transcode = async () => {\n        const ffmpeg = ffmpegRef.current;\n        await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm'));\n        await ffmpeg.writeFile('reversed.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s_reversed.webm'));\n        await ffmpeg.exec([\n            '-i',\n            'input.webm',\n            '-i',\n            'reversed.webm',\n            '-filter_complex',\n            '[0:v][1:v]blend=all_expr=\\'A*(if(eq(0,N/2),1,T))+B*(if(eq(0,N/2),T,1))\\'',\n            'output.mp4',\n        ]);\n        const data = await ffmpeg.readFile('output.mp4');\n        videoRef.current.src =\n            URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));\n    }\n\n    return (loaded\n        ? (\n            <>\n                <video ref={videoRef} controls></video><br/>\n                <button onClick={transcode}>Interlace two webm video to mp4</button>\n                <p ref={messageRef}></p>\n                <p>Open Developer Tools (Ctrl+Shift+I) to View Logs</p>\n            </>\n        )\n        : (\n            <button onClick={load}>Load ffmpeg-core (~31 MB)</button>\n        )\n    );\n}\n```\n\n## Use WORKERFS\n\n:::note\nRequired:\n\n- @ffmpeg/ffmpeg@0.12.10+\n- @ffmpeg/core@0.12.4+\n  :::\n\nPlease Check this PR: [Add WORKERFS support](https://github.com/ffmpegwasm/ffmpeg.wasm/pull/581)\n\n## Abort exec() with signal\n\n:::note\nRequired:\n\n- @ffmpeg/ffmpeg@0.12.10+\n- @ffmpeg/core@0.12.4+\n  :::\n\nPlease check this PR: [abort signal](https://github.com/ffmpegwasm/ffmpeg.wasm/pull/573)\n"
  },
  {
    "path": "apps/website/docs/migration.md",
    "content": "import MuiThemeProvider from \"@site/src/components/common/MuiThemeProvider\";\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport Paper from '@mui/material/Paper';\n\n# Migrating from 0.11.x to 0.12+\n\nAs 0.12+ is not backward compatible with 0.11.x, below is a quick mapping\ntable to transform 0.11.x to 0.12+\n\n<MuiThemeProvider>\n    <TableContainer>\n      <Table sx={{ minWidth: 650 }} aria-label=\"simple table\">\n        <TableHead>\n          <TableRow>\n            <TableCell align=\"center\">0.11.x</TableCell>\n            <TableCell align=\"center\">0.12+</TableCell>\n            <TableCell align=\"center\">Note</TableCell>\n          </TableRow>\n        </TableHead>\n        <TableBody>\n          {[\n            {\"0.11.x\": \"import { createFFmpeg } from '@ffmpeg/ffmpeg'\", \"0.12+\": \"import { FFmpeg } from '@ffmpeg/ffmpeg'\", note: \"\"},\n            {\"0.11.x\": \"createFFmpeg()\", \"0.12+\": \"new FFmpeg()\", note: \"argumens of createFFmpeg() is moved to ffmpeg.load()\"},\n            {\"0.11.x\": \"await ffmpeg.load()\", \"0.12+\": \"await ffmpeg.load()\", note: \"\"},\n            {\"0.11.x\": \"await ffmpeg.run(...args)\", \"0.12+\": \"await ffmpeg.exec([...args])\", note: \"\"},\n            {\"0.11.x\": \"ffmpeg.FS.writeFile()\", \"0.12+\": \"await ffmpeg.writeFile()\", note: \"\"},\n            {\"0.11.x\": \"ffmpeg.FS.readFile()\", \"0.12+\": \"await ffmpeg.readFile()\", note: \"\"},\n            {\"0.11.x\": \"ffmpeg.exit()\", \"0.12+\": \"ffmpeg.terminate()\", note: \"\"},\n            {\"0.11.x\": \"ffmpeg.setLogger()\", \"0.12+\": \"ffmpeg.on(\\\"log\\\", () => {})\", note: \"\"},\n            {\"0.11.x\": \"ffmpeg.setProgress()\", \"0.12+\": \"ffmpeg.on(\\\"progress\\\", () => {})\", note: \"\"},\n            {\"0.11.x\": \"import { fetchFile } from '@ffmpeg/ffmpeg'\", \"0.12+\": \"import { fetchFile } from '@ffmpeg/util'\", note: \"\"},\n           ].map((row) => (\n            <TableRow\n              key={row['0.11.x']}\n            >\n              <TableCell component=\"th\" scope=\"row\">\n                {row['0.11.x']}\n              </TableCell>\n              <TableCell align=\"left\">{row['0.12+']}</TableCell>\n              <TableCell align=\"left\">{row.note}</TableCell>\n            </TableRow>\n          ))}\n        </TableBody>\n      </Table>\n    </TableContainer>\n</MuiThemeProvider>\n"
  },
  {
    "path": "apps/website/docs/overview.md",
    "content": "import MuiThemeProvider from \"@site/src/components/common/MuiThemeProvider\";\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport Paper from '@mui/material/Paper';\n\n# Overview\n\n:::info\nFor 0.11.x, visit [https://ffmpegwasm-0-11-x.netlify.app](https://ffmpegwasm-0-11-x.netlify.app)\nand [0.11.x](https://github.com/ffmpegwasm/ffmpeg.wasm/tree/0.11.x) branch.\n:::\n\n## Introduction\n\nffmpeg.wasm is a pure WebAssembly / JavaScript port of [FFmpeg](https://www.ffmpeg.org/)\nenabling video & audio record, convert and stream right inside browsers.\n\nWe leverage\n[Emscripten](https://emscripten.org/) to transpile FFmpeg source code and many\nlibraries to WebAssembly and develop a minimal but essential library to free\ndevelopers from common requirements like running ffmpeg inside web worker and\nmore.\n\n## Advantages\n\n- **Security**: your users' data only lives inside their browser, no need to\n    worry about any data leakage or network latency.\n- **Client-side computing**: instead of hosting a cluster of server-end servers,\n    you can now offload multimedia processing to client-side.\n- **Flexible**: ffmpeg.wasm comes with single-thread and multi-thread cores, you\n    can use whichever fits your use case.\n\n## Architecture\n\n![architecture](/img/ffmpegwasm-arch.png)\n\nMultimedia transcoding is a resource-intensive task that you don't want to\nexecute in main thread, thus in ffmpeg.wasm we offload those task to web worker\n(`ffmpeg.worker`) by default. This makes almost all function calls in ffmpeg.wasm\nare asynchronous and it is recommended to use **async** / **await** syntax.\n\n`ffmpeg.worker` downloads WebAssembly code (`ffmpeg-core`) from CDN\nand initialized it in WorkerGlobalScope. For any input video file you would like\nto process, you need to first populated them inside ffmpeg-core File System and\nalso read result from `ffmpeg-core` File System once it is done.\n\nIf you are using a multi-thread version of `ffmpeg-core`, more web workers will\nbe spawned by `ffmpeg-core` inside `ffmpeg.worker`\n\n:::info\nThe concept of `core` in ffmpeg.wasm is like the engine of a car, it is not only\nthe most important part of ffmpeg.wasm but also a swappable component. Currently\nwe maintain single-thread (`@ffmpeg/core`) and multi-thread version\n(`@ffmpeg/core-mt`) cores, you can build your own core (ex. a core with x264\n lib only to minimize ffmpeg-core.wasm file size) using build scripts in the repository.\n:::\n\n## Packages\n\nAll ffmpeg.wasm packages are under [@ffmpeg](https://www.npmjs.com/search?q=%40ffmpeg)\nname space:\n\n| Name | Usage |\n| ---- | ----- |\n| @ffmpeg/ffmpeg | ffmpeg.wasm main package |\n| @ffmpeg/util | common utility functions |\n| @ffmpeg/types | TypeScript types |\n| @ffmpeg/core | single-thread ffmpeg.wasm core |\n| @ffmpeg/core-mt | multi-thread ffmpeg.wasm core |\n\n## Libraries\n\nffmpeg.wasm is built with toolchains / libraries:\n\n<MuiThemeProvider>\n    <TableContainer>\n      <Table sx={{ minWidth: 650 }} aria-label=\"simple table\">\n        <TableHead>\n          <TableRow>\n            <TableCell align=\"center\">Name</TableCell>\n            <TableCell align=\"center\">Version</TableCell>\n            <TableCell align=\"center\">Note</TableCell>\n          </TableRow>\n        </TableHead>\n        <TableBody>\n          {[\n            {name: \"Emscripten\", version: \"3.1.40\", note: \"Emscripten is a toolchain for compiling C and C++ code into WebAssembly and JavaScript, making it possible to run applications written in these languages in web browsers.\"},\n            {name: \"FFmpeg\", version: \"n5.1.4\", note: \"FFmpeg is a powerful multimedia framework that can decode, encode, transcode, and stream audio and video files. It's widely used for media manipulation and streaming.\"},\n            {name: \"x264\", version: \"0.164.x\", note: \"x264 is a popular video encoding library that provides high-quality H.264 video compression. It's commonly used for video encoding and transcoding.\"},\n            {name: \"x265\", version: \"3.4\", note: \"x265 is a video encoding library that specializes in encoding videos using the H.265/HEVC codec, offering high compression efficiency for video content.\"},\n            {name: \"libvpx\", version: \"v1.13.1\", note: \"libvpx is an open-source video codec library used for encoding and decoding VP8 and VP9 video formats, commonly used for web-based video streaming.\"},\n            {name: \"lame\", version: \"3.100\", note: \"LAME is an audio encoder that converts audio files to the MP3 format, making it widely used for creating MP3 audio files.\"},\n            {name: \"ogg\", version: \"v1.3.4\", note: \"Ogg is a multimedia container format, and this library provides support for encoding and decoding audio and video in the Ogg format.\"},\n            {name: \"theora\", version: \"v1.1.1\", note: \"Theora is an open video codec designed for efficient video compression within the Ogg multimedia framework.\"},\n            {name: \"opus\", version: \"v1.3.1\", note: \"Opus is a versatile audio codec capable of handling both voice and music with low latency and high-quality compression.\"},\n            {name: \"vorbis\", version: \"v1.3.3\", note: \"Vorbis is an open-source audio codec known for its high audio quality and efficient compression. It's often used for audio streaming.\"},\n            {name: \"zlib\", version: \"v1.2.11\", note: \"zlib is a compression library that provides data compression and decompression functionality, commonly used in file compression formats like gzip.\"},\n            {name: \"libwebp\", version: \"v1.3.2\", note: \"libwebp is a library for working with the WebP image format, offering efficient image compression for web use\"},\n            {name: \"freetype2\", version: \"v2.10.4\", note: \"FreeType 2 is a library for rendering fonts. It is commonly used for text rendering in applications and systems.\"},\n            {name: \"fribidi\", version: \"v1.0.9\", note: \"FriBidi is a library for handling bidirectional text (text containing both left-to-right and right-to-left scripts) and is often used in text layout and rendering.\"},\n            {name: \"harfbuzz\", version: \"5.2.0\", note: \"HarfBuzz is a text shaping engine that allows complex script text to be rendered correctly. It's used in conjunction with font rendering libraries.\"},\n            {name: \"libass\", version: \"0.15.0\", note: \"libass is a library for rendering and formatting subtitles in multimedia applications, making it essential for displaying subtitles alongside video content.\"},\n            {name: \"zimg\", version: \"3.0.5\", note: \"zimg implements the commonly required image processing basics of scaling, colorspace conversion, and depth conversion.\"}\n           ].map((row) => (\n            <TableRow\n              key={row.name}\n            >\n              <TableCell component=\"th\" scope=\"row\">\n                {row.name}\n              </TableCell>\n              <TableCell align=\"left\">{row.version}</TableCell>\n              <TableCell align=\"left\">{row.note}</TableCell>\n            </TableRow>\n          ))}\n        </TableBody>\n      </Table>\n    </TableContainer>\n</MuiThemeProvider>\n"
  },
  {
    "path": "apps/website/docs/performance.md",
    "content": "# Performance\n\nffmpeg.wasm uses transpiled FFmpeg C source code to WebAssembly code, it is for\ncertain that ffmpeg.wasm won't perform as good as FFmpeg as it is not fully\noptimized at the moment. (Even in ffmpeg.wasm multithread version). In this\nsection we provide a short comparison, so that you can make decision based on your\nneeds:\n\n## Environment\n\n- CPU: 8 × 11th Gen Intel® Core™ i5-1135G7 @ 2.40GHz\n- Memory: 15.6 GiB of RAM\n- OS: Manjaro Linux 6.1.44-1-MANJARO (64-bit)\n- Browser: Google Chrome Version 116.0.5845.96 (Official Build) (64-bit)\n- FFmpeg: n5.1.2\n\n## Comparison\n\nSetup:\n\n- Each command is executed 5 times.\n- Only `ffmpeg.exec()` time is measured.\n- Candidates\n  - FFmpeg: [native FFmpeg](https://hub.docker.com/r/linuxserver/ffmpeg),\n      considered as baseline.\n  - core: ffmpeg.wasm single thread version.\n  - core-mt: ffmpeg.wasm multi thread version.\n\n### $ ffmpeg -i [input.webm](https://test-videos.co.uk/vids/bigbuckbunny/webm/vp8/720/Big_Buck_Bunny_720_10s_1MB.webm) output.mp4\n\n|  #  | FFmpeg | core v0.12.3 | core-mt v0.12.3 |\n| --- | ------ | ------------ | --------------- |\n| Avg | 5.2 sec | 128.8 sec (0.04x) | 60.4 sec (0.08x) |\n| Max | 5.3 sec | 130.7 sec | 63.9 sec |\n| Min | 5.1 sec | 126.6 sec | 59 sec |\n"
  },
  {
    "path": "apps/website/docs/privacy-policy.md",
    "content": "# Privacy Policy\n<p>Last updated: August 05, 2023</p>\n<p>This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.</p>\n<p>We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the <a href=\"https://www.freeprivacypolicy.com/free-privacy-policy-generator/\" target=\"_blank\">Free Privacy Policy Generator</a>.</p>\n<h1>Interpretation and Definitions</h1>\n<h2>Interpretation</h2>\n<p>The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.</p>\n<h2>Definitions</h2>\n<p>For the purposes of this Privacy Policy:</p>\n<ul>\n<li>\n<p><strong>Account</strong> means a unique account created for You to access our Service or parts of our Service.</p>\n</li>\n<li>\n<p><strong>Affiliate</strong> means an entity that controls, is controlled by or is under common control with a party, where &quot;control&quot; means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority.</p>\n</li>\n<li>\n<p><strong>Company</strong> (referred to as either &quot;the Company&quot;, &quot;We&quot;, &quot;Us&quot; or &quot;Our&quot; in this Agreement) refers to ffmpeg.wasm.</p>\n</li>\n<li>\n<p><strong>Cookies</strong> are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.</p>\n</li>\n<li>\n<p><strong>Country</strong> refers to:  Singapore</p>\n</li>\n<li>\n<p><strong>Device</strong> means any device that can access the Service such as a computer, a cellphone or a digital tablet.</p>\n</li>\n<li>\n<p><strong>Personal Data</strong> is any information that relates to an identified or identifiable individual.</p>\n</li>\n<li>\n<p><strong>Service</strong> refers to the Website.</p>\n</li>\n<li>\n<p><strong>Service Provider</strong> means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.</p>\n</li>\n<li>\n<p><strong>Usage Data</strong> refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).</p>\n</li>\n<li>\n<p><strong>Website</strong> refers to ffmpeg.wasm, accessible from <a href=\"https://ffmpegwasm.netlify.app/\" rel=\"external nofollow noopener\" target=\"_blank\">https://ffmpegwasm.netlify.app/</a></p>\n</li>\n<li>\n<p><strong>You</strong> means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.</p>\n</li>\n</ul>\n<h1>Collecting and Using Your Personal Data</h1>\n<h2>Types of Data Collected</h2>\n<h3>Personal Data</h3>\n<p>While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:</p>\n<ul>\n<li>Usage Data</li>\n</ul>\n<h3>Usage Data</h3>\n<p>Usage Data is collected automatically when using the Service.</p>\n<p>Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.</p>\n<p>When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.</p>\n<p>We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.</p>\n<h3>Tracking Technologies and Cookies</h3>\n<p>We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:</p>\n<ul>\n<li><strong>Cookies or Browser Cookies.</strong> A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.</li>\n<li><strong>Web Beacons.</strong> Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).</li>\n</ul>\n<p>Cookies can be &quot;Persistent&quot; or &quot;Session&quot; Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. Learn more about cookies on the <a href=\"https://www.freeprivacypolicy.com/blog/sample-privacy-policy-template/#Use_Of_Cookies_And_Tracking\" target=\"_blank\">Free Privacy Policy website</a> article.</p>\n<p>We use both Session and Persistent Cookies for the purposes set out below:</p>\n<ul>\n<li>\n<p><strong>Necessary / Essential Cookies</strong></p>\n<p>Type: Session Cookies</p>\n<p>Administered by: Us</p>\n<p>Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.</p>\n</li>\n<li>\n<p><strong>Cookies Policy / Notice Acceptance Cookies</strong></p>\n<p>Type: Persistent Cookies</p>\n<p>Administered by: Us</p>\n<p>Purpose: These Cookies identify if users have accepted the use of cookies on the Website.</p>\n</li>\n<li>\n<p><strong>Functionality Cookies</strong></p>\n<p>Type: Persistent Cookies</p>\n<p>Administered by: Us</p>\n<p>Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.</p>\n</li>\n</ul>\n<p>For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.</p>\n<h2>Use of Your Personal Data</h2>\n<p>The Company may use Personal Data for the following purposes:</p>\n<ul>\n<li>\n<p><strong>To provide and maintain our Service</strong>, including to monitor the usage of our Service.</p>\n</li>\n<li>\n<p><strong>To manage Your Account:</strong> to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.</p>\n</li>\n<li>\n<p><strong>For the performance of a contract:</strong> the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.</p>\n</li>\n<li>\n<p><strong>To contact You:</strong> To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.</p>\n</li>\n<li>\n<p><strong>To provide You</strong> with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.</p>\n</li>\n<li>\n<p><strong>To manage Your requests:</strong> To attend and manage Your requests to Us.</p>\n</li>\n<li>\n<p><strong>For business transfers:</strong> We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.</p>\n</li>\n<li>\n<p><strong>For other purposes</strong>: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.</p>\n</li>\n</ul>\n<p>We may share Your personal information in the following situations:</p>\n<ul>\n<li><strong>With Service Providers:</strong> We may share Your personal information with Service Providers to monitor and analyze the use of our Service,  to contact You.</li>\n<li><strong>For business transfers:</strong> We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.</li>\n<li><strong>With Affiliates:</strong> We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.</li>\n<li><strong>With business partners:</strong> We may share Your information with Our business partners to offer You certain products, services or promotions.</li>\n<li><strong>With other users:</strong> when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside.</li>\n<li><strong>With Your consent</strong>: We may disclose Your personal information for any other purpose with Your consent.</li>\n</ul>\n<h2>Retention of Your Personal Data</h2>\n<p>The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.</p>\n<p>The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.</p>\n<h2>Transfer of Your Personal Data</h2>\n<p>Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.</p>\n<p>Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.</p>\n<p>The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.</p>\n<h2>Delete Your Personal Data</h2>\n<p>You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You.</p>\n<p>Our Service may give You the ability to delete certain information about You from within the Service.</p>\n<p>You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us.</p>\n<p>Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so.</p>\n<h2>Disclosure of Your Personal Data</h2>\n<h3>Business Transactions</h3>\n<p>If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.</p>\n<h3>Law enforcement</h3>\n<p>Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).</p>\n<h3>Other legal requirements</h3>\n<p>The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:</p>\n<ul>\n<li>Comply with a legal obligation</li>\n<li>Protect and defend the rights or property of the Company</li>\n<li>Prevent or investigate possible wrongdoing in connection with the Service</li>\n<li>Protect the personal safety of Users of the Service or the public</li>\n<li>Protect against legal liability</li>\n</ul>\n<h2>Security of Your Personal Data</h2>\n<p>The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.</p>\n<h1>Children's Privacy</h1>\n<p>Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.</p>\n<p>If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.</p>\n<h1>Links to Other Websites</h1>\n<p>Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.</p>\n<p>We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.</p>\n<h1>Changes to this Privacy Policy</h1>\n<p>We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.</p>\n<p>We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the &quot;Last updated&quot; date at the top of this Privacy Policy.</p>\n<p>You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.</p>\n<h1>Contact Us</h1>\n<p>If you have any questions about this Privacy Policy, You can contact us:</p>\n<ul>\n<li>By email: jeromewus@gmail.com</li>\n</ul>\n"
  },
  {
    "path": "apps/website/docusaurus.config.js",
    "content": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require(\"prism-react-renderer/themes/github\");\nconst darkCodeTheme = require(\"prism-react-renderer/themes/dracula\");\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: \"ffmpeg.wasm\",\n  tagline:\n    \"ffmpeg.wasm is a pure WebAssembly / JavaScript port of FFmpeg enabling video & audio record, convert and stream right inside browsers!\",\n  url: \"https://ffmpegwasm.netlify.app\",\n  baseUrl: \"/\",\n  onBrokenLinks: \"throw\",\n  onBrokenMarkdownLinks: \"warn\",\n  favicon: \"img/favicon.ico\",\n\n  // GitHub pages deployment config.\n  // If you aren't using GitHub pages, you don't need these.\n  organizationName: \"ffmpegwasm\", // Usually your GitHub org/user name.\n  projectName: \"ffmpeg.wasm\", // Usually your repo name.\n\n  // Even if you don't use internalization, you can use this field to set useful\n  // metadata like html lang. For example, if your site is Chinese, you may want\n  // to replace \"en\" with \"zh-Hans\".\n  i18n: {\n    defaultLocale: \"en\",\n    locales: [\"en\"],\n  },\n\n  presets: [\n    [\n      \"classic\",\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: require.resolve(\"./sidebars.js\"),\n          // Please change this to your repo.\n          // Remove this to remove the \"edit this page\" links.\n          editUrl:\n            \"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/website\",\n        },\n        blog: {\n          showReadingTime: true,\n          // Please change this to your repo.\n          // Remove this to remove the \"edit this page\" links.\n          editUrl:\n            \"https://github.com/ffmpegwasm/ffmpeg.wasm/tree/main/apps/website\",\n        },\n        theme: {\n          customCss: [\n            require.resolve(\"./src/css/custom.css\"),\n            require.resolve(\"@fontsource/roboto/300.css\"),\n            require.resolve(\"@fontsource/roboto/400.css\"),\n            require.resolve(\"@fontsource/roboto/500.css\"),\n            require.resolve(\"@fontsource/roboto/700.css\"),\n          ],\n        },\n        gtag: {\n          trackingID: \"G-8NBTQ7N6RB\",\n          anonymizeIP: true,\n        },\n      }),\n    ],\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      navbar: {\n        title: \"ffmpeg.wasm\",\n        logo: {\n          alt: \"ffmpeg.wasm Logo\",\n          src: \"img/logo192.png\",\n        },\n        items: [\n          {\n            type: \"doc\",\n            docId: \"overview\",\n            position: \"left\",\n            label: \"Docs\",\n          },\n          { to: \"/playground\", label: \"Playground\", position: \"left\" },\n          { to: \"/blog\", label: \"Blog\", position: \"left\" },\n          {\n            href: \"https://github.com/ffmpegwasm/ffmpeg.wasm\",\n            label: \"GitHub\",\n            position: \"right\",\n          },\n        ],\n      },\n      footer: {\n        style: \"dark\",\n        links: [\n          {\n            title: \"Docs\",\n            items: [\n              {\n                label: \"Tutorial\",\n                to: \"/docs/overview\",\n              },\n            ],\n          },\n          {\n            title: \"Community\",\n            items: [\n              {\n                label: \"Stack Overflow\",\n                href: \"https://stackoverflow.com/questions/tagged/ffmpeg.wasm\",\n              },\n              {\n                label: \"Discord\",\n                href: \"https://discord.gg/NjGMaqqfm5\",\n              },\n            ],\n          },\n          {\n            title: \"More\",\n            items: [\n              {\n                label: \"Blog\",\n                to: \"/blog\",\n              },\n              {\n                label: \"GitHub\",\n                href: \"https://github.com/ffmpegwasm/ffmpeg.wasm\",\n              },\n            ],\n          },\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} ffmpeg.wasm, Inc. Built with Docusaurus.`,\n      },\n      prism: {\n        theme: lightCodeTheme,\n        darkTheme: darkCodeTheme,\n        additionalLanguages: ['docker'],\n      },\n    }),\n  plugins: [\n    [require.resolve('@easyops-cn/docusaurus-search-local'), {\n      indexDocs: true,\n      indexBlog: true,\n      hashed: true,\n    }],\n    [\n      \"docusaurus-plugin-typedoc\",\n      {\n        id: \"ffmpeg\",\n        entryPoints: [\"../../packages/ffmpeg/src/index.ts\"],\n        tsconfig: \"../../packages/ffmpeg/tsconfig.json\",\n        readme: \"none\",\n        out: \"api/ffmpeg\",\n        sidebar: {\n          indexLabel: \"@ffmpeg/ffmpeg\",\n          fullNames: true,\n        },\n      },\n    ],\n    [\n      \"docusaurus-plugin-typedoc\",\n      {\n        id: \"util\",\n        entryPoints: [\"../../packages/util/src/index.ts\"],\n        tsconfig: \"../../packages/util/tsconfig.json\",\n        readme: \"none\",\n        out: \"api/util\",\n        sidebar: {\n          indexLabel: \"@ffmpeg/util\",\n          fullNames: true,\n        },\n      },\n    ],\n  ],\n  themes: [\"@docusaurus/theme-live-codeblock\"],\n  scripts: [\n    {\n      src: \"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8688083214014126\",\n      async: true,\n      crossorigin: \"anonymous\",\n    },\n  ],\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "apps/website/netlify.toml",
    "content": "[[headers]]\n  for = \"/*\"\n  [headers.values]\n  Cross-Origin-Opener-Policy = \"same-origin\"\n  Cross-Origin-Embedder-Policy = \"require-corp\"\n"
  },
  {
    "path": "apps/website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.12.0-alpha.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"build:packages\": \"cd ../.. && npm run build\",\n    \"clean\": \"rm -rf docs/api\",\n    \"prestart\": \"npm run clean && npm run build:packages\",\n    \"start\": \"docusaurus start\",\n    \"prebuild\": \"npm run clean && npm run build:packages\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\",\n    \"typecheck\": \"tsc\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^2.4.1\",\n    \"@docusaurus/preset-classic\": \"^2.4.1\",\n    \"@docusaurus/theme-live-codeblock\": \"^2.4.1\",\n    \"@emotion/react\": \"^11.10.4\",\n    \"@emotion/styled\": \"^11.10.4\",\n    \"@ffmpeg/ffmpeg\": \"*\",\n    \"@ffmpeg/util\": \"*\",\n    \"@fontsource/roboto\": \"^4.5.8\",\n    \"@mdx-js/react\": \"^1.6.22\",\n    \"@mui/icons-material\": \"^5.10.6\",\n    \"@mui/material\": \"^5.10.8\",\n    \"clsx\": \"^1.2.1\",\n    \"prism-react-renderer\": \"^1.3.5\",\n    \"react\": \"^17.0.2\",\n    \"react-ace\": \"^10.1.0\",\n    \"react-dom\": \"^17.0.2\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"^2.2.0\",\n    \"@easyops-cn/docusaurus-search-local\": \"^0.34.0\",\n    \"@tsconfig/docusaurus\": \"^1.0.5\",\n    \"@types/ace\": \"^0.0.48\",\n    \"docusaurus-plugin-typedoc\": \"^0.17.5\",\n    \"typedoc\": \"^0.23.15\",\n    \"typedoc-plugin-markdown\": \"^3.13.6\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=18.17\"\n  }\n}\n"
  },
  {
    "path": "apps/website/sidebars.js",
    "content": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that group\n - provide next/previous navigation\n\n The sidebars can be generated from the filesystem, or explicitly defined here.\n\n Create as many sidebars as you want.\n */\n\n// @ts-check\n\n/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  // By default, Docusaurus generates a sidebar from the docs folder structure\n  // tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],\n\n  // But you can create a sidebar manually\n  tutorialSidebar: [\n    \"overview\",\n    {\n      type: \"category\",\n      label: \"Getting Started\",\n      items: [\n        \"getting-started/installation\",\n        \"getting-started/usage\",\n        \"getting-started/examples\",\n      ],\n    },\n    \"performance\",\n    \"migration\",\n    \"faq\",\n    {\n      type: \"category\",\n      label: \"API\",\n      items: [\"api/ffmpeg/index\", \"api/util/index\"],\n    },\n    {\n      type: \"category\",\n      label: \"Contribution\",\n      items: [\"contribution/core\", \"contribution/ffmpeg\", \"contribution/util\"],\n    },\n    {\n      type: \"doc\",\n      label: \"Privacy Policy\",\n      id: \"privacy-policy\",\n    },\n  ],\n};\n\nmodule.exports = sidebars;\n"
  },
  {
    "path": "apps/website/src/components/ExternalLibraries/index.tsx",
    "content": "import React from \"react\";\nimport clsx from \"clsx\";\nimport styles from \"./styles.module.css\";\n\ninterface LibraryItem {\n  title: string;\n  desc: string;\n  img: string;\n  isBlackBackground?: boolean;\n}\n\nconst libs: LibraryItem[] = [\n  {\n    title: \"x264\",\n    desc: \"H.264 Codec\",\n    img: require(\"@site/static/img/libs/x264.png\").default,\n    isBlackBackground: true,\n  },\n  {\n    title: \"x265\",\n    desc: \"H.265 codec\",\n    img: require(\"@site/static/img/libs/x265.webp\").default,\n  },\n  {\n    title: \"libvpx\",\n    desc: \"VP8/VP9 codec\",\n    img: require(\"@site/static/img/libs/libvpx.png\").default,\n  },\n  {\n    title: \"theora\",\n    desc: \"OGV codec\",\n    img: require(\"@site/static/img/libs/theora.png\").default,\n  },\n  {\n    title: \"lame\",\n    desc: \"MP3 codec\",\n    img: require(\"@site/static/img/libs/lame.gif\").default,\n  },\n  {\n    title: \"vorbis\",\n    desc: \"OGG codec\",\n    img: require(\"@site/static/img/libs/vorbis.png\").default,\n  },\n  {\n    title: \"opus\",\n    desc: \"OPUS codec\",\n    img: require(\"@site/static/img/libs/opus.png\").default,\n  },\n  {\n    title: \"freetype2\",\n    desc: \"Font file renderer\",\n    img: require(\"@site/static/img/libs/freetype.png\").default,\n  },\n  {\n    title: \"libass\",\n    desc: \"subtitle renderer\",\n    img: require(\"@site/static/img/libs/freetype.png\").default,\n  },\n  {\n    title: \"libwebp\",\n    desc: \"WEBP codec\",\n    img: require(\"@site/static/img/libs/webp.png\").default,\n  },\n];\n\nfunction Library({ title, desc, img, isBlackBackground = false }: LibraryItem) {\n  return (\n    <div className={clsx(\"col col--2\")}>\n      <div className=\"text--center\">\n        <img\n          src={img}\n          className={clsx(\n            styles.libraryImg,\n            isBlackBackground && styles.blackBackground\n          )}\n        />\n      </div>\n      <div className=\"text--center padding-horiz--md\">\n        <h3>{title}</h3>\n        <p>{desc}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default function ExternalLibraries(): JSX.Element {\n  return (\n    <section className={styles.libraries}>\n      <div className=\"container\">\n        <h1 className=\"text--center\">External Libraries</h1>\n        <h4 className=\"text--center\">\n          {\" \"}\n          ffmpeg.wasm is built with common external libraries, and more of\n          libraries to be added!\n        </h4>\n        <div className=\"row\">\n          {libs.map((props, idx) => (\n            <Library key={idx} {...props} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/ExternalLibraries/styles.module.css",
    "content": ".libraries {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n  background-color: rgba(229,231,235, 1);\n  color: #1b1b1d;\n}\n\n.libraryImg {\n  height: 96px;\n  padding: 16px;\n}\n\n.blackBackground {\n  background-color: #1b1b1d;\n}\n"
  },
  {
    "path": "apps/website/src/components/HomepageFeatures/index.tsx",
    "content": "import React from \"react\";\nimport clsx from \"clsx\";\nimport styles from \"./styles.module.css\";\n\ntype FeatureItem = {\n  title: string;\n  Svg: React.ComponentType<React.ComponentProps<\"svg\">>;\n  description: JSX.Element;\n};\n\nconst FeatureList: FeatureItem[] = [\n  {\n    title: \"Data Security\",\n    Svg: require(\"@site/static/img/safety-icon.svg\").default,\n    description: (\n      <>\n        ffmpeg.wasm runs only inside your browser, data security is guaranteed as\n        no data is sent to remote server.\n      </>\n    ),\n  },\n  {\n    title: \"Powered by WebAssembly\",\n    Svg: require(\"@site/static/img/wasm-logo.svg\").default,\n    description: (\n      <>\n        ffmpeg.wasm transpiles <a href=\"https://ffmpeg.org/\">ffmpeg</a> source\n        code to WebAssembly code using\n        <a href=\"https://emscripten.org/\"> Emscripten</a> to achieve optimal\n        performance.\n      </>\n    ),\n  },\n  {\n    title: \"Made with TypeScript\",\n    Svg: require(\"@site/static/img/ts-logo-round-512.svg\").default,\n    description: (\n      <>\n        ffmpeg.wasm is written in TypeScript to provide great developer\n        experience (DX).\n      </>\n    ),\n  },\n];\n\nfunction Feature({ title, Svg, description }: FeatureItem) {\n  return (\n    <div className={clsx(\"col col--4\")}>\n      <div className=\"text--center\">\n        <Svg className={styles.featureSvg} role=\"img\" />\n      </div>\n      <div className=\"text--center padding-horiz--md\">\n        <h3>{title}</h3>\n        <p>{description}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default function HomepageFeatures(): JSX.Element {\n  return (\n    <section className={styles.features}>\n      <div className=\"container\">\n        <div className=\"row\">\n          {FeatureList.map((props, idx) => (\n            <Feature key={idx} {...props} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/HomepageFeatures/styles.module.css",
    "content": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureSvg {\n  height: 200px;\n  width: 200px;\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/CoreDownloader.tsx",
    "content": "import * as React from \"react\";\nimport Typography from \"@mui/material/Typography\";\nimport Container from \"@mui/material/Container\";\nimport LinearProgressWithLabel from \"@site/src/components/common/LinearProgressWithLabel\";\nimport { CORE_SIZE } from \"./const\";\n\nexport default function CoreDownloader({ url, received }) {\n  const total = CORE_SIZE[url];\n  return (\n    <Container>\n      <Typography>{`Downloading ${url}`}</Typography>\n      <Typography>{`(${received} / ${total} bytes)`}</Typography>\n      <LinearProgressWithLabel value={(received / total) * 100} />\n    </Container>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/CoreSwitcher.tsx",
    "content": "import React from \"react\";\nimport Stack from \"@mui/material/Stack\";\nimport FormGroup from \"@mui/material/FormGroup\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport Switch from \"@mui/material/Switch\";\nimport IconButton from \"@mui/material/IconButton\";\nimport HelpIcon from \"@mui/icons-material/HelpOutline\";\nimport Tooltip from \"@mui/material/Tooltip\";\n\ninterface CoreSwitcherProps {\n  checked: boolean;\n  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;\n}\n\nexport default function CoreSwitcher({ checked, onChange }: CoreSwitcherProps) {\n  return (\n    <>\n      <Stack direction=\"row\" justifyContent=\"flex-end\">\n        <FormGroup>\n          <FormControlLabel\n            control={<Switch checked={checked} onChange={onChange} />}\n            label=\"Use Multithreading\"\n            disabled={typeof SharedArrayBuffer !== \"function\"}\n          />\n        </FormGroup>\n        <Tooltip title=\"Multi-threaded core is faster, but unstable and not supported by all browsers.\">\n          <IconButton aria-label=\"help\" size=\"small\">\n            <HelpIcon fontSize=\"small\" />\n          </IconButton>\n        </Tooltip>\n      </Stack>\n    </>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/Workspace/Editor.tsx",
    "content": "/// <reference types=\"ace\" />\n\nimport React, { useEffect, useState } from \"react\";\nimport AceEditor from \"react-ace\";\nimport Paper from \"@mui/material/Paper\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Button from \"@mui/material/Button\";\nimport LinearProgressWithLabel from \"@site/src/components/common/LinearProgressWithLabel\";\nimport { useColorMode } from \"@docusaurus/theme-common\";\nimport \"ace-builds/src-noconflict/mode-json\";\nimport \"ace-builds/src-noconflict/mode-javascript\";\nimport \"ace-builds/src-noconflict/mode-text\";\nimport \"ace-builds/src-noconflict/theme-dracula\";\nimport \"ace-builds/src-noconflict/theme-github\";\n\nconst genFFmpegText = (args: string) => {\n  let data: any = [];\n  try {\n    data = JSON.parse(args);\n  } catch (e) {}\n  return `// equivalent ffmpeg.wasm API call\nffmpeg.exec(${JSON.stringify(data)});\n\n// equivalent ffmpeg command line\nffmpeg ${data.join(\" \")}`;\n};\n\ninterface EditorProps {\n  args: string;\n  logs: string[];\n  progress: number;\n  time: number;\n  onArgsUpdate: (args: string) => void;\n  onExec: () => Promise<void>;\n}\n\nexport default function Editor({\n  args = \"\",\n  logs = [],\n  progress = 0,\n  time = 0,\n  onArgsUpdate,\n  onExec,\n}: EditorProps) {\n  const { colorMode } = useColorMode();\n  const [output, setOutput] = useState<Ace.Editor>();\n\n  useEffect(() => {\n    // scroll logs to the end.\n    output && output.renderer.scrollToLine(Number.POSITIVE_INFINITY);\n  }, [logs]);\n\n  const theme = colorMode === \"dark\" ? \"github\" : \"dracula\";\n\n  return (\n    <Paper variant=\"outlined\" style={{ padding: 8, height: \"100%\" }}>\n      <Stack spacing={1}>\n        <Stack>\n          <Typography>Editor:</Typography>\n          <Typography>Edit arguments below to update command:</Typography>\n          <AceEditor\n            mode=\"json\"\n            theme={theme}\n            name=\"input-args\"\n            fontSize={16}\n            showPrintMargin={true}\n            showGutter={true}\n            width=\"100%\"\n            minLines={8}\n            maxLines={8}\n            highlightActiveLine={true}\n            value={args}\n            onChange={onArgsUpdate}\n            setOptions={{ tabSize: 2, useWorker: false }}\n          />\n        </Stack>\n        <AceEditor\n          mode=\"javascript\"\n          theme={theme}\n          name=\"ffmpeg.wasm\"\n          fontSize={16}\n          showGutter={false}\n          width=\"100%\"\n          minLines={6}\n          maxLines={6}\n          readOnly\n          highlightActiveLine={false}\n          value={genFFmpegText(args)}\n          setOptions={{ tabSize: 2, useWorker: false }}\n        />\n        <Typography>Console Output:</Typography>\n        <AceEditor\n          mode=\"text\"\n          theme={theme}\n          name=\"console\"\n          fontSize={16}\n          width=\"100%\"\n          minLines={8}\n          maxLines={8}\n          readOnly\n          showPrintMargin={true}\n          highlightActiveLine={false}\n          value={logs.join(\"\\n\")}\n          setOptions={{ tabSize: 2, useWorker: false }}\n          onLoad={(editor) => setOutput(editor)}\n        />\n        <Typography>Transcoding Progress:</Typography>\n        <LinearProgressWithLabel value={progress} />\n        <Stack direction=\"row\" spacing={2} justifyContent=\"space-between\">\n          <Typography>\n            {time === 0 ? \"\" : `Time Elapsed: ${(time / 1000).toFixed(2)} s`}\n          </Typography>\n          <Button variant=\"contained\" onClick={onExec}>\n            Run\n          </Button>\n        </Stack>\n      </Stack>\n    </Paper>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/Workspace/FileSystemManager.tsx",
    "content": "import React, { useState, ChangeEvent } from \"react\";\nimport Box from \"@mui/material/Box\";\nimport Button from \"@mui/material/Button\";\nimport IconButton from \"@mui/material/IconButton\";\nimport List from \"@mui/material/List\";\nimport ListItem from \"@mui/material/ListItem\";\nimport ListItemButton from \"@mui/material/ListItemButton\";\nimport ListItemIcon from \"@mui/material/ListItemIcon\";\nimport ListItemText from \"@mui/material/ListItemText\";\nimport Modal from \"@mui/material/Modal\";\nimport Paper from \"@mui/material/Paper\";\nimport Stack from \"@mui/material/Stack\";\nimport TextField from \"@mui/material/TextField\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport Typography from \"@mui/material/Typography\";\nimport FolderIcon from \"@mui/icons-material/Folder\";\nimport RefreshIcon from \"@mui/icons-material/Refresh\";\nimport UploadFileIcon from \"@mui/icons-material/UploadFile\";\nimport UploadIcon from \"@mui/icons-material/Upload\";\nimport InsertDriveFileIcon from \"@mui/icons-material/InsertDriveFile\";\nimport CreateNewFolderIcon from \"@mui/icons-material/CreateNewFolder\";\nimport MoreButton from \"./MoreButton\";\nimport { Node } from \"./types\";\n\ninterface FileSystemManagerProps {\n  path: string;\n  nodes: Node[];\n  oldName: string;\n  newName: string;\n  renameOpen: boolean;\n  onNewNameChange: () => (event: ChangeEvent<HTMLInputElement>) => Promise<void>;\n  onCloseRenameModal: () => () => Promise<void>;\n  onFileUpload: (\n    isText: boolean\n  ) => (event: ChangeEvent<HTMLInputElement>) => Promise<void>;\n  onDirClick: (name: string) => () => Promise<void>;\n  onFileClick: (name: string) => (option: string) => Promise<void>;\n  onDirCreate: (name: string) => () => Promise<void>;\n  onRename: (old_name: string, new_name: string) => () => Promise<void>;\n  onRefresh: () => Promise<void>;\n  onLoadSamples: () => Promise<void>;\n}\n\nconst modalStyle = {\n  position: \"absolute\" as \"absolute\",\n  top: \"50%\",\n  left: \"50%\",\n  transform: \"translate(-50%, -50%)\",\n  width: 400,\n  bgcolor: \"background.paper\",\n  p: 4,\n};\n\nexport const options = [\n  { text: \"Rename\", key: \"rename\" },\n  { text: \"Download\", key: \"download\" },\n  { text: \"Download as Text File\", key: \"download-text\" },\n  { text: \"Delete\", key: \"delete\" },\n];\n\nexport default function FileSystemManager({\n  path = \"/\",\n  nodes = [],\n  oldName = \"\",\n  newName = \"\",\n  renameOpen = false,\n  onNewNameChange = () => () => Promise.resolve(),\n  onCloseRenameModal = () => () => Promise.resolve(),\n  onFileUpload = () => () => Promise.resolve(),\n  onFileClick = () => () => Promise.resolve(),\n  onDirClick = () => () => Promise.resolve(),\n  onDirCreate = () => () => Promise.resolve(),\n  onRename = () => () => Promise.resolve(),\n  onRefresh = () => Promise.resolve(),\n  onLoadSamples = () => Promise.resolve(),\n}: FileSystemManagerProps) {\n  const [newFolderOpen, setNewFolderOpen] = useState(false);\n  const [dirName, setDirName] = useState(\"\");\n  const handleNewFolderModalOpen = () => setNewFolderOpen(true);\n  const handleNewFolderModalClose = () => setNewFolderOpen(false);\n\n  return (\n    <>\n      <Paper variant=\"outlined\" style={{ padding: 8, height: \"100%\" }}>\n        <Stack justifyContent=\"space-between\" style={{ height: \"100%\" }}>\n          <>\n            <Stack\n              direction=\"row\"\n              justifyContent=\"space-between\"\n              alignItems=\"center\"\n            >\n              <Typography>File System:</Typography>\n              <Box>\n                <Tooltip title=\"Upload a media file\">\n                  <IconButton\n                    aria-label=\"upload-media-file\"\n                    component=\"label\"\n                    size=\"small\"\n                  >\n                    <input\n                      hidden\n                      multiple\n                      type=\"file\"\n                      onChange={onFileUpload(false)}\n                    />\n                    <UploadFileIcon fontSize=\"small\" />\n                  </IconButton>\n                </Tooltip>\n                <Tooltip title=\"Upload a text file\">\n                  <IconButton\n                    onClick={() => {}}\n                    aria-label=\"upload-text\"\n                    component=\"label\"\n                    size=\"small\"\n                  >\n                    <input\n                      hidden\n                      multiple\n                      type=\"file\"\n                      onChange={onFileUpload(true)}\n                    />\n                    <UploadIcon fontSize=\"small\" />\n                  </IconButton>\n                </Tooltip>\n                <Tooltip title=\"Create a new folder\">\n                  <IconButton\n                    onClick={() => {\n                      setDirName(\"\");\n                      handleNewFolderModalOpen();\n                    }}\n                    aria-label=\"create-a-new-folder\"\n                    size=\"small\"\n                  >\n                    <CreateNewFolderIcon />\n                  </IconButton>\n                </Tooltip>\n                <Tooltip title=\"Refresh directory\">\n                  <IconButton\n                    onClick={onRefresh}\n                    aria-label=\"fresh\"\n                    size=\"small\"\n                  >\n                    <RefreshIcon fontSize=\"small\" />\n                  </IconButton>\n                </Tooltip>\n              </Box>\n            </Stack>\n            <Typography>{`Path: ${path}`}</Typography>\n            <List style={{ height: 480, overflowX: \"auto\" }}>\n              {nodes.map(({ name, isDir }, index) =>\n                isDir ? (\n                  <ListItemButton key={index} onClick={onDirClick(name)}>\n                    <ListItemIcon>\n                      <FolderIcon />\n                    </ListItemIcon>\n                    <ListItemText primary={name} />\n                  </ListItemButton>\n                ) : (\n                  <ListItem\n                    key={index}\n                    secondaryAction={\n                      <MoreButton\n                        options={options}\n                        onItemClick={onFileClick(name)}\n                      />\n                    }\n                  >\n                    <ListItemIcon>\n                      <InsertDriveFileIcon />\n                    </ListItemIcon>\n                    <ListItemText primary={name} />\n                  </ListItem>\n                )\n              )}\n            </List>\n          </>\n          <Button onClick={onLoadSamples}>Load Sample Files</Button>\n        </Stack>\n      </Paper>\n      <Modal\n        open={newFolderOpen}\n        onClose={handleNewFolderModalClose}\n        aria-labelledby=\"new-folder-name\"\n        aria-describedby=\"new-folder-name-description\"\n      >\n        <Box sx={modalStyle}>\n          <Stack spacing={4}>\n            <Typography id=\"modal-modal-title\" variant=\"h6\" component=\"h2\">\n              Folder Name:\n            </Typography>\n            <TextField\n              id=\"outlined-basic\"\n              label=\"my-folder\"\n              variant=\"outlined\"\n              value={dirName}\n              onChange={(event) => setDirName(event.target.value)}\n            />\n            <Stack direction=\"row\" justifyContent=\"flex-end\">\n              <Button onClick={handleNewFolderModalClose}>Cancel</Button>\n              <Button\n                variant=\"contained\"\n                onClick={() => {\n                  onDirCreate(dirName);\n                  handleNewFolderModalClose();\n                }}\n              >\n                Create\n              </Button>\n            </Stack>\n          </Stack>\n        </Box>\n      </Modal>\n      <Modal\n        open={renameOpen}\n        onClose={onCloseRenameModal()}\n        aria-labelledby=\"new-name\"\n        aria-describedby=\"new-name-description\"\n      >\n        <Box sx={modalStyle}>\n          <Stack spacing={4}>\n            <Typography id=\"modal-modal-title\" variant=\"h6\" component=\"h2\">\n              New Name:\n            </Typography>\n            <TextField\n              id=\"outlined-basic\"\n              label=\"my-file\"\n              variant=\"outlined\"\n              value={newName}\n              onChange={onNewNameChange()}\n            />\n            <Stack direction=\"row\" justifyContent=\"flex-end\">\n              <Button onClick={onCloseRenameModal()}>Cancel</Button>\n              <Button\n                variant=\"contained\"\n                onClick={onRename(oldName, newName)}\n              >\n                Rename\n              </Button>\n            </Stack>\n          </Stack>\n        </Box>\n      </Modal>\n    </>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/Workspace/MoreButton.tsx",
    "content": "import * as React from \"react\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Menu from \"@mui/material/Menu\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport MoreVertIcon from \"@mui/icons-material/MoreVert\";\n\nconst ITEM_HEIGHT = 48;\n\ninterface Option {\n  key: string;\n  text: string;\n}\n\ninterface MoreButtonProps {\n  options: Option[];\n  onItemClick: (option: string) => any;\n}\n\nexport default function MoreButton({ options, onItemClick }: MoreButtonProps) {\n  const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);\n  const open = Boolean(anchorEl);\n  const handleClick = (event: React.MouseEvent<HTMLElement>) => {\n    setAnchorEl(event.currentTarget);\n  };\n  const handleClose = () => {\n    setAnchorEl(null);\n  };\n\n  const handleItemClick = (option: string) => () => {\n    onItemClick(option);\n    setAnchorEl(null);\n  };\n\n  return (\n    <div>\n      <IconButton\n        aria-label=\"more\"\n        id=\"more-button\"\n        aria-controls={open ? \"menu\" : undefined}\n        aria-expanded={open ? \"true\" : undefined}\n        aria-haspopup=\"true\"\n        onClick={handleClick}\n      >\n        <MoreVertIcon />\n      </IconButton>\n      <Menu\n        id=\"menu\"\n        MenuListProps={{\n          \"aria-labelledby\": \"more-button\",\n        }}\n        anchorEl={anchorEl}\n        open={open}\n        onClose={handleClose}\n        PaperProps={{\n          style: {\n            maxHeight: ITEM_HEIGHT * 4.5,\n            width: \"20ch\",\n          },\n        }}\n      >\n        {options.map(({ text, key }) => (\n          <MenuItem key={key} onClick={handleItemClick(key)}>\n            {text}\n          </MenuItem>\n        ))}\n      </Menu>\n    </div>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/Workspace/index.tsx",
    "content": "import React, {\n  ChangeEvent,\n  useState,\n  useEffect,\n  MutableRefObject,\n} from \"react\";\nimport Box from \"@mui/material/Box\";\nimport Grid from \"@mui/material/Grid\";\nimport { FFmpeg } from \"@ffmpeg/ffmpeg\";\nimport { fetchFile } from \"@ffmpeg/util\";\nimport { downloadFile } from \"@site/src/util\";\nimport { Node } from \"./types\";\nimport FileSystemManager from \"./FileSystemManager\";\nimport { SAMPLE_FILES } from \"../const\";\nimport Editor from \"./Editor\";\n\nconst defaultArgs = JSON.stringify([\"-i\", \"video.webm\", \"video.mp4\"], null, 2);\n\ninterface WorkspaceProps {\n  ffmpeg: MutableRefObject<FFmpeg>;\n}\n\nexport default function Workspace({ ffmpeg: _ffmpeg }: WorkspaceProps) {\n  const [path, setPath] = useState(\"/\");\n  const [nodes, setNodes] = useState<Node[]>([]);\n  const [oldName, setOldName] = useState(\"\");\n  const [newName, setNewName] = useState(\"\");\n  const [renameOpen, setRenameOpen] = useState(false);\n  const [args, setArgs] = useState(defaultArgs);\n  const [progress, setProgress] = useState(0);\n  const [time, setTime] = useState(0);\n  const [logs, setLogs] = useState<string[]>([]);\n\n  const ffmpeg = _ffmpeg.current;\n\n  const refreshDir = async (curPath: string) => {\n    if (ffmpeg.loaded) {\n      setNodes(\n        (await ffmpeg.listDir(curPath)).filter(({ name }) => name !== \".\")\n      );\n    }\n  };\n\n  const onNewNameChange = () => async (event: ChangeEvent<HTMLInputElement>) => {\n    setNewName(event.target.value);\n  };\n\n  const onCloseRenameModal = () => async () => {\n    setRenameOpen(false);\n  };\n\n  const onFileUpload =\n    (isText: boolean) =>\n    async ({ target: { files } }: ChangeEvent<HTMLInputElement>) => {\n      for (let i = 0; i < files.length; i++) {\n        const file = files[i];\n        let data: Uint8Array | string = await fetchFile(file);\n        if (isText) data = new TextDecoder().decode(data);\n        await ffmpeg.writeFile(`${path}/${file.name}`, data);\n      }\n      refreshDir(path);\n    };\n\n  const onFileClick = (name: string) => async (option: string) => {\n    const fullPath = `${path}/${name}`;\n    switch (option) {\n      case \"rename\":\n        setOldName(name);\n        setNewName(\"\");\n        setRenameOpen(true);\n        break;\n      case \"download\":\n        downloadFile(\n          name,\n          ((await ffmpeg.readFile(fullPath, \"binary\")) as Uint8Array).buffer\n        );\n        break;\n      case \"download-text\":\n        downloadFile(name, await ffmpeg.readFile(fullPath, \"utf8\"));\n        break;\n      case \"delete\":\n        await ffmpeg.deleteFile(fullPath);\n        refreshDir(path);\n        break;\n      default:\n        break;\n    }\n  };\n\n  const onDirClick = (name: string) => async () => {\n    let nextPath = path;\n    if (path === \"/\") {\n      if (name !== \"..\") nextPath = `/${name}`;\n    } else if (name === \"..\") {\n      const cols = path.split(\"/\");\n      cols.pop();\n      nextPath = cols.length === 1 ? \"/\" : cols.join(\"/\");\n    } else {\n      nextPath = `${path}/${name}`;\n    }\n    setPath(nextPath);\n    refreshDir(nextPath);\n  };\n\n  const onDirCreate = (name: string) => async () => {\n    if (name !== \"\") {\n      await ffmpeg.createDir(`${path}/${name}`);\n    }\n    refreshDir(path);\n  };\n\n  const onRename = (old_name: string, new_name: string) => async () => {\n    if (old_name !== \"\" && new_name !== \"\") {\n      await ffmpeg.rename(`${path}/${old_name}`, `${path}/${new_name}`);\n    }\n    setRenameOpen(false);\n    refreshDir(path);\n  };\n\n  const onLoadSamples = async () => {\n    for (const name of Object.keys(SAMPLE_FILES)) {\n      await ffmpeg.writeFile(name, await fetchFile(SAMPLE_FILES[name]));\n    }\n    refreshDir(path);\n  };\n\n  const onExec = async () => {\n    setProgress(0);\n    setTime(0);\n    const logListener = ({ message }) => {\n      setLogs((_logs) => [..._logs, message]);\n    };\n    const progListener = ({ progress: prog }) => {\n      setProgress(prog * 100);\n    };\n    ffmpeg.on(\"log\", logListener);\n    ffmpeg.on(\"progress\", progListener);\n    const start = performance.now();\n    await ffmpeg.exec(JSON.parse(args));\n    setTime(performance.now() - start);\n    ffmpeg.off(\"log\", logListener);\n    ffmpeg.off(\"progress\", progListener);\n    refreshDir(path);\n  };\n\n  useEffect(() => {\n    refreshDir(path);\n  }, []);\n\n  return (\n    <Box sx={{ flexGrow: 1 }}>\n      <Grid container spacing={{ xs: 1 }} columns={{ xs: 4, md: 12 }}>\n        <Grid item xs={4}>\n          <FileSystemManager\n            path={path}\n            nodes={nodes}\n            oldName={oldName}\n            newName={newName}\n            renameOpen={renameOpen}\n            onNewNameChange={onNewNameChange}\n            onCloseRenameModal={onCloseRenameModal}\n            onFileUpload={onFileUpload}\n            onFileClick={onFileClick}\n            onDirClick={onDirClick}\n            onDirCreate={onDirCreate}\n            onRename={onRename}\n            onLoadSamples={onLoadSamples}\n            onRefresh={() => refreshDir(path)}\n          />\n        </Grid>\n        <Grid item xs={8}>\n          <Editor\n            args={args}\n            logs={logs}\n            progress={progress}\n            time={time}\n            onArgsUpdate={(_args) => setArgs(_args)}\n            onExec={onExec}\n          />\n        </Grid>\n      </Grid>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/Workspace/types.tsx",
    "content": "export interface Node {\n  name: string;\n  isDir: boolean;\n}\n"
  },
  {
    "path": "apps/website/src/components/Playground/const.ts",
    "content": "export const CORE_VERSION = \"0.12.10\";\n\nexport const CORE_URL = `https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;\nexport const CORE_MT_URL = `https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;\n\nexport const CORE_SIZE = {\n  [`https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`]: 114673,\n  [`https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.wasm`]: 32129114,\n  [`https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.js`]: 132680,\n  [`https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.wasm`]: 32609891,\n  [`https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.worker.js`]: 2915,\n};\n\nexport const SAMPLE_FILES = {\n  \"video.webm\":\n    \"https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm\",\n};\n"
  },
  {
    "path": "apps/website/src/components/Playground/index.tsx",
    "content": "import React, { useState, useEffect, useRef } from \"react\";\nimport { FFmpeg } from \"@ffmpeg/ffmpeg\";\nimport { toBlobURL } from \"@ffmpeg/util\";\nimport Stack from \"@mui/material/Stack\";\nimport MuiThemeProvider from \"@site/src/components/common/MuiThemeProvider\";\nimport CoreDownloader from \"./CoreDownloader\";\nimport Workspace from \"./Workspace\";\nimport { CORE_URL, CORE_MT_URL } from \"./const\";\nimport CoreSwitcher from \"./CoreSwitcher\";\n\nenum State {\n  NOT_LOADED,\n  LOADING,\n  LOADED,\n}\n\nexport default function Playground() {\n  const [state, setState] = useState(State.LOADED);\n  const [isCoreMT, setIsCoreMT] = useState(false);\n  const [url, setURL] = useState(\"\");\n  const [received, setReceived] = useState(0);\n  const ffmpeg = useRef(new FFmpeg());\n\n  const load = async (mt: boolean = false) => {\n    setState(State.LOADING);\n    const setProgress = ({ url: _url, received: _received }) => {\n      setURL(_url as string);\n      setReceived(_received);\n    };\n    const coreURL = await toBlobURL(\n      mt ? CORE_MT_URL : CORE_URL,\n      \"text/javascript\",\n      true,\n      setProgress\n    );\n    const wasmURL = await toBlobURL(\n      mt\n        ? CORE_MT_URL.replace(/.js$/g, \".wasm\")\n        : CORE_URL.replace(/.js$/g, \".wasm\"),\n      \"application/wasm\",\n      true,\n      setProgress\n    );\n    const workerURL = mt\n      ? await toBlobURL(\n          CORE_MT_URL.replace(/.js$/g, \".worker.js\"),\n          \"text/javascript\",\n          true,\n          setProgress\n        )\n      : \"\";\n    ffmpeg.current.terminate();\n    await ffmpeg.current.load({\n      coreURL,\n      wasmURL,\n      workerURL,\n    });\n    setState(State.LOADED);\n  };\n\n  useEffect(() => {\n    load(isCoreMT);\n  }, []);\n\n  return (\n    <MuiThemeProvider>\n      <Stack spacing={4}>\n        <CoreSwitcher\n          checked={isCoreMT}\n          onChange={(evt) => {\n            setIsCoreMT(evt.target.checked);\n            load(evt.target.checked);\n          }}\n        />\n        {(() => {\n          switch (state) {\n            case State.LOADING:\n              return <CoreDownloader url={url} received={received} />;\n            case State.LOADED:\n              return <Workspace ffmpeg={ffmpeg} />;\n            default:\n              return <></>;\n          }\n        })()}\n      </Stack>\n    </MuiThemeProvider>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/common/ExampleCard.tsx",
    "content": "import * as React from \"react\";\nimport Card from \"@mui/material/Card\";\nimport CardContent from \"@mui/material/CardContent\";\nimport CardMedia from \"@mui/material/CardMedia\";\nimport CardActions from \"@mui/material/CardActions\";\nimport Button from \"@mui/material/Button\";\nimport Typography from \"@mui/material/Typography\";\n\nexport default function ActionAreaCard({ img, title, desc, url }) {\n  return (\n    <Card sx={{ maxWidth: 320 }}>\n      <CardMedia\n        component=\"img\"\n        height=\"180\"\n        image={img}\n        alt=\"framework image\"\n      />\n      <CardContent>\n        <Typography gutterBottom variant=\"h5\" component=\"div\">\n          {title}\n        </Typography>\n        <Typography variant=\"body2\" color=\"text.secondary\">\n          {desc}\n        </Typography>\n      </CardContent>\n      <CardActions>\n        <Button\n          size=\"small\"\n          color=\"primary\"\n          onClick={() => {\n            window.open(url, \"_blank\");\n          }}\n        >\n          Open\n        </Button>\n      </CardActions>\n    </Card>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/common/LinearProgressWithLabel.tsx",
    "content": "import * as React from \"react\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport LinearProgress, {\n  LinearProgressProps,\n} from \"@mui/material/LinearProgress\";\n\nexport default function LinearProgressWithLabel(\n  props: LinearProgressProps & { value: number }\n) {\n  return (\n    <Box sx={{ display: \"flex\", alignItems: \"center\" }}>\n      <Box sx={{ width: \"100%\", mr: 1 }}>\n        <LinearProgress variant=\"determinate\" {...props} />\n      </Box>\n      <Box sx={{ minWidth: 35 }}>\n        <Typography variant=\"body2\" color=\"text.secondary\">{`${Math.round(\n          props.value\n        )}%`}</Typography>\n      </Box>\n    </Box>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/common/MuiThemeProvider/index.tsx",
    "content": "import React from \"react\";\nimport { useColorMode } from \"@docusaurus/theme-common\";\nimport { ThemeProvider, createTheme } from \"@mui/material/styles\";\n\nconst lightTheme = createTheme({});\nconst darkTheme = createTheme({\n  palette: {\n    mode: \"dark\",\n  },\n});\n\nexport default function MuiThemeProvider(props: any) {\n  const { colorMode } = useColorMode();\n  return (\n    <ThemeProvider\n      theme={colorMode === \"dark\" ? darkTheme : lightTheme}\n      {...props}\n    />\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/common/ThemedButton/index.tsx",
    "content": "import React from \"react\";\nimport MuiThemeProvider from \"../MuiThemeProvider\";\nimport Button, { ButtonProps } from \"@mui/material/Button\";\n\nexport default function ThemedButton(props: ButtonProps) {\n  return (\n    <MuiThemeProvider>\n      <Button {...props} />\n    </MuiThemeProvider>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/components/common/ThemedIconButton/index.tsx",
    "content": "import React from \"react\";\nimport MuiThemeProvider from \"../MuiThemeProvider\";\nimport IconButton, { IconButtonProps } from \"@mui/material/IconButton\";\n\nexport default function ThemedIconButton(props: IconButtonProps) {\n  return (\n    <MuiThemeProvider>\n      <IconButton {...props} />\n    </MuiThemeProvider>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/css/custom.css",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n    --ifm-color-primary: #654ff0;\n  --ifm-color-primary-dark: #4b32ed;\n  --ifm-color-primary-darker: #3e23ec;\n  --ifm-color-primary-darkest: #2b12ce;\n  --ifm-color-primary-light: #7f6cf3;\n  --ifm-color-primary-lighter: #8c7bf4;\n  --ifm-color-primary-lightest: #b2a7f8;\n  --ifm-code-font-size: 95%;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);\n}\n\n/* For readability concerns, you should choose a lighter palette in dark mode. */\n[data-theme='dark'] {\n    --ifm-color-primary: #cac2ff;\n  --ifm-color-primary-dark: #a395ff;\n  --ifm-color-primary-darker: #8f7fff;\n  --ifm-color-primary-darkest: #553bff;\n  --ifm-color-primary-light: #f1efff;\n  --ifm-color-primary-lighter: #ffffff;\n  --ifm-color-primary-lightest: #ffffff;\n  --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);\n}\n"
  },
  {
    "path": "apps/website/src/pages/index.module.css",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 2rem;\n  }\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n"
  },
  {
    "path": "apps/website/src/pages/index.tsx",
    "content": "import React from \"react\";\nimport clsx from \"clsx\";\nimport Link from \"@docusaurus/Link\";\nimport useDocusaurusContext from \"@docusaurus/useDocusaurusContext\";\nimport Layout from \"@theme/Layout\";\nimport HomepageFeatures from \"@site/src/components/HomepageFeatures\";\nimport ExternalLibraries from \"@site/src/components/ExternalLibraries\";\n\nimport styles from \"./index.module.css\";\n\nfunction HomepageHeader() {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <header className={clsx(\"hero hero--primary\", styles.heroBanner)}>\n      <div className=\"container\">\n        <h1 className=\"hero__title\">{siteConfig.title}</h1>\n        <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n        <div className={styles.buttons}>\n          <Link\n            className=\"button button--secondary button--lg\"\n            to=\"/playground\"\n          >\n            Try it Now!\n          </Link>\n        </div>\n      </div>\n    </header>\n  );\n}\n\nexport default function Home(): JSX.Element {\n  const { siteConfig } = useDocusaurusContext();\n  return (\n    <Layout\n      title={`${siteConfig.title}`}\n      description=\"ffmpeg.wasm is a pure WebAssembly / JavaScript port of FFmpeg\"\n    >\n      <HomepageHeader />\n      <main>\n        <HomepageFeatures />\n        <ExternalLibraries />\n      </main>\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "apps/website/src/pages/playground.md",
    "content": "import BrowserOnly from '@docusaurus/BrowserOnly';\nimport MuiThemeProvider from \"@site/src/components/common/MuiThemeProvider\";\nimport ThemedButton from \"@site/src/components/common/ThemedButton\";\nimport ThemedIconButton from \"@site/src/components/common/ThemedIconButton\";\nimport CreateNewFolderIcon from \"@mui/icons-material/CreateNewFolder\";\nimport RefreshIcon from \"@mui/icons-material/Refresh\";\nimport UploadFileIcon from \"@mui/icons-material/UploadFile\";\nimport UploadIcon from \"@mui/icons-material/Upload\";\n\n# Playground\n\nPlayground allows you to try ffmpeg.wasm without any installation and\ndevelopment!\n\n:::tip Quick Start\n\n1. Wait for assets (~32 MB) downloading.\n2. Press <ThemedButton>Load Sample Files</ThemedButton> to download & add sample files.\n3. Press <ThemedButton variant=\"contained\">Run</ThemedButton> to convert an AVI file to MP4 file.\n4. Download output files.\n\n:::\n\n<BrowserOnly>\n  {() => {\n    const Playground = require('@site/src/components/Playground').default;\n    return <Playground/>\n  }}\n</BrowserOnly>\n\n<div style={{ height: 32 }} />\n\n:::tip\nDemo Video: [https://youtu.be/F01B0fV20QA](https://youtu.be/F01B0fV20QA)\n:::\n\n## How to Use :rocket:\n\n> It is recommended to read [Overview](/docs/overview) first to learn\nffmpeg.wasm fundamentals.\n\nA typical flow to use ffmpeg.wasm is:\n\n#### Download and load JavaScript & WebAssembly assets\n\nThe assets are downloaded automatically when you enter the Playground. You can\nchoose to use multithreading version instead by click on the switch:\n\n<MuiThemeProvider>\n  <BrowserOnly>\n  {() => {\n    const CoreSwitcher = require('@site/src/components/Playground/CoreSwitcher').default;\n    return <CoreSwitcher/>;\n  }}\n  </BrowserOnly>\n</MuiThemeProvider>\n\n#### Load files to in-memory File System\n\nWhen ffmpeg.wasm is loaded and ready, you can upload files to its in-memory File\nSystem to make sure these files can be consumed by the ffmpeg.wasm APIs:\n\n<div style={{ maxWidth: 260 }}>\n  <MuiThemeProvider>\n    <BrowserOnly>\n    {() => {\n      const FileSystemManager = require('@site/src/components/Playground/Workspace/FileSystemManager').default;\n      return (\n        <FileSystemManager\n          nodes={[\n            {name: \"..\", isDir: true},\n            {name: \"tmp\", isDir: true},\n            {name: \"home\", isDir: true},\n            {name: \"dev\", isDir: true},\n            {name: \"proc\", isDir: true},\n            {name: \"video.avi\", isDir: false},\n          ]}\n        />\n      );\n    }}\n    </BrowserOnly>\n  </MuiThemeProvider>\n</div>\n\n<div style={{ height: 32 }} />\n\n- <ThemedIconButton size=\"small\"><UploadFileIcon fontSize=\"small\"\n    /></ThemedIconButton>: Upload a media file.\n- <ThemedIconButton size=\"small\"><UploadIcon fontSize=\"small\"\n    /></ThemedIconButton>: Upload a text file.\n- <ThemedIconButton size=\"small\"><CreateNewFolderIcon fontSize=\"small\"\n    /></ThemedIconButton>: Create a new folder.\n- <ThemedIconButton size=\"small\"><RefreshIcon fontSize=\"small\"\n    /></ThemedIconButton>: Refresh File System.\n\n> Press <ThemedButton>Load Sample Files</ThemedButton> to load a set of samples\nfiles.\n\n#### Run a command \n\nWith files are ready in the File System, you can update arguments in the Editor\nand hit <ThemedButton variant=\"contained\">Run</ThemedButton> afterward:\n\n<div style={{ maxWidth: 480 }}>\n  <MuiThemeProvider>\n    <BrowserOnly>\n    {() => {\n      const Editor = require('@site/src/components/Playground/Workspace/Editor').default;\n      return (\n        <Editor args={JSON.stringify([\"-i\", \"video.avi\", \"video.mp4\"], null, 2)} />\n      );\n    }}\n    </BrowserOnly>\n  </MuiThemeProvider>\n</div>\n\n<div style={{ height: 32 }} />\n\n#### Download output files\n\nLastly you can download your files using File System panel and check the result.\n:tada:\n"
  },
  {
    "path": "apps/website/src/theme/ReactLiveScope/index.js",
    "content": "import React from \"react\";\nimport { FFmpeg } from \"@ffmpeg/ffmpeg\";\nimport { fetchFile, toBlobURL } from \"@ffmpeg/util\";\n\n// Add react-live imports you need here\nconst ReactLiveScope = {\n  React,\n  ...React,\n  FFmpeg,\n  fetchFile,\n  toBlobURL,\n};\nexport default ReactLiveScope;\n"
  },
  {
    "path": "apps/website/src/util.ts",
    "content": "export const downloadFile = (name: string, data: ArrayBuffer | string) => {\n  const a = document.createElement(\"a\");\n  const blob = new Blob([data]);\n  const url = window.URL.createObjectURL(blob);\n  a.href = url;\n  a.download = name;\n  a.click();\n  window.URL.revokeObjectURL(url);\n};\n"
  },
  {
    "path": "apps/website/static/.nojekyll",
    "content": ""
  },
  {
    "path": "apps/website/static/ads.txt",
    "content": "google.com, pub-8688083214014126, DIRECT, f08c47fec0942fa0\n"
  },
  {
    "path": "apps/website/tsconfig.json",
    "content": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@tsconfig/docusaurus/tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\"\n  }\n}\n"
  },
  {
    "path": "build/aom.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCM_FLAGS=(\n  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR           # assign lib and include install path\n  -DCMAKE_TOOLCHAIN_FILE=$EM_TOOLCHAIN_FILE     # use emscripten toolchain file\n  -DBUILD_SHARED_LIBS=0                         # disable shared library build\n  -DAOM_TARGET_CPU=generic                      # use generic cpu\n  -DENABLE_DOCS=0                               # disable docs\n  -DENABLE_TESTS=0                              # disable tests\n  -DENABLE_EXAMPLES=0                           # disable examples\n  -DENABLE_TOOLS=0                              # disable tools\n  -DCONFIG_RUNTIME_CPU_DETECT=0                 # disable cpu detect\n  -DCONFIG_WEBM_IO=0                            # disable libwebm support\n)\n\nCMBUILD_DIR=cmbuild\nrm -rf $CMBUILD_DIR\nmkdir -p $CMBUILD_DIR\ncd $CMBUILD_DIR\n\nemmake cmake .. \\\n  -DAOM_EXTRA_C_FLAGS=\"$CFLAGS\" \\\n  -DAOM_EXTRA_CXX_FLAGS=\"$CFLAGS\" \\\n  ${CM_FLAGS[@]}\nemmake make install -j\n"
  },
  {
    "path": "build/ffmpeg-wasm.sh",
    "content": "#!/bin/bash\n# `-o <OUTPUT_FILE_NAME>` must be provided when using this build script.\n# ex:\n#     bash ffmpeg-wasm.sh -o ffmpeg.js\n\nset -euo pipefail\n\nEXPORT_NAME=\"createFFmpegCore\"\n\nCONF_FLAGS=(\n  -I. \n  -I./src/fftools \n  -I$INSTALL_DIR/include \n  -L$INSTALL_DIR/lib \n  -Llibavcodec \n  -Llibavdevice \n  -Llibavfilter \n  -Llibavformat \n  -Llibavutil \n  -Llibpostproc \n  -Llibswresample \n  -Llibswscale \n  -lavcodec \n  -lavdevice \n  -lavfilter \n  -lavformat \n  -lavutil \n  -lpostproc \n  -lswresample \n  -lswscale \n  -Wno-deprecated-declarations \n  $LDFLAGS \n  -sENVIRONMENT=worker\n  -sWASM_BIGINT                            # enable big int support\n  -sUSE_SDL=2                              # use emscripten SDL2 lib port\n  -sSTACK_SIZE=5MB                         # increase stack size to support libopus\n  -sMODULARIZE                             # modularized to use as a library\n  ${FFMPEG_MT:+ -sINITIAL_MEMORY=1024MB}   # ALLOW_MEMORY_GROWTH is not recommended when using threads, thus we use a large initial memory\n  ${FFMPEG_MT:+ -sPTHREAD_POOL_SIZE=32}    # use 32 threads\n  ${FFMPEG_ST:+ -sINITIAL_MEMORY=32MB -sALLOW_MEMORY_GROWTH} # Use just enough memory as memory usage can grow\n  -sEXPORT_NAME=\"$EXPORT_NAME\"             # required in browser env, so that user can access this module from window object\n  -sEXPORTED_FUNCTIONS=$(node src/bind/ffmpeg/export.js) # exported functions\n  -sEXPORTED_RUNTIME_METHODS=$(node src/bind/ffmpeg/export-runtime.js) # exported built-in functions\n  -lworkerfs.js\n  --pre-js src/bind/ffmpeg/bind.js        # extra bindings, contains most of the ffmpeg.wasm javascript code\n  # ffmpeg source code\n  src/fftools/cmdutils.c \n  src/fftools/ffmpeg.c \n  src/fftools/ffmpeg_filter.c \n  src/fftools/ffmpeg_hw.c \n  src/fftools/ffmpeg_mux.c \n  src/fftools/ffmpeg_opt.c \n  src/fftools/opt_common.c \n  src/fftools/ffprobe.c \n)\n\nemcc \"${CONF_FLAGS[@]}\" $@\n"
  },
  {
    "path": "build/ffmpeg.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --target-os=none              # disable target specific configs\n  --arch=x86_32                 # use x86_32 arch\n  --enable-cross-compile        # use cross compile configs\n  --disable-asm                 # disable asm\n  --disable-stripping           # disable stripping as it won't work\n  --disable-programs            # disable ffmpeg, ffprobe and ffplay build\n  --disable-doc                 # disable doc build\n  --disable-debug               # disable debug mode\n  --disable-runtime-cpudetect   # disable cpu detection\n  --disable-autodetect          # disable env auto detect\n\n  # assign toolchains and extra flags\n  --nm=emnm\n  --ar=emar\n  --ranlib=emranlib\n  --cc=emcc\n  --cxx=em++\n  --objcc=emcc\n  --dep-cc=emcc\n  --extra-cflags=\"$CFLAGS\"\n  --extra-cxxflags=\"$CXXFLAGS\"\n\n  # disable thread when FFMPEG_ST is NOT defined\n  ${FFMPEG_ST:+ --disable-pthreads --disable-w32threads --disable-os2threads}\n)\n\nemconfigure ./configure \"${CONF_FLAGS[@]}\" $@\nemmake make -j\n"
  },
  {
    "path": "build/freetype2.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=x86_64-gnu                                   # use i686 linux\n  --enable-shared=no                                  # not to build shared library\n  --without-harfbuzz                                  # disable harfbuzz as incompatible\n)\nemconfigure ./autogen.sh\nemconfigure ./configure \"${CONF_FLAGS[@]}\"\n# build apinames manually to prevent it built by emcc\ngcc -o objs/apinames src/tools/apinames.c\nemmake make install -j\n"
  },
  {
    "path": "build/fribidi.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=x86_64-linux\n  --enable-shared=no                                  # not to build shared library\n  --enable-static=yes\n  --disable-dependency-tracking\n  --disable-debug\n)\nemconfigure ./autogen.sh \"${CONF_FLAGS[@]}\"\n# A hacky to fix \"Too many symbolic links\" error\nemmake make install -j || true\nmkdir -p $INSTALL_DIR/lib/pkgconfig && cp fribidi.pc $INSTALL_DIR/lib/pkgconfig/\n"
  },
  {
    "path": "build/harfbuzz.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCFLAGS=\"$CFLAGS -DHB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR\"\n\n# A hacky way to disable pthread\nif [[ \"$FFMPEG_ST\" == \"yes\" ]]; then\n  sed -i 's#\\[have_pthread=true\\]#\\[have_pthread=false\\]#g' configure.ac\nelse\n  sed -i 's#\\[have_pthread=false\\]#\\[have_pthread=true\\]#g' configure.ac\nfi\nCXXFLAGS=$CFLAGS\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                                 # install library in a build directory for FFmpeg to include\n  --host=i686-gnu                                     # use i686 linux\n  --enable-shared=no                                  # not to build shared library\n  --enable-static \n)\n\nemconfigure ./autogen.sh \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/lame.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=i686-linux                                   # use i686 linux\n  --disable-shared                                    # disable shared library\n  --disable-frontend                                  # exclude lame executable\n  --disable-analyzer-hooks                            # exclude analyzer hooks\n  --disable-dependency-tracking                       # speed up one-time build\n  --disable-gtktest\n)\nCFLAGS=$CFLAGS emconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/libass.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=i686-gnu                                     # use i686 linux\n  --disable-shared\n  --enable-static\n  --disable-asm                                       # disable asm optimization\n  --disable-fontconfig\n  --disable-require-system-font-provider\n)\n\n./autogen.sh && emconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/libvpx.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                              # install library in a build directory for FFmpeg to include\n  --target=generic-gnu                               # target with miminal features\n  --disable-install-bins                             # not to install bins\n  --disable-examples                                 # not to build examples\n  --disable-tools                                    # not to build tools\n  --disable-docs                                     # not to build docs\n  --disable-unit-tests                               # not to do unit tests\n  --disable-dependency-tracking                      # speed up one-time build\n  --extra-cflags=\"$CFLAGS\"                           # flags to use pthread and code optimization\n  --extra-cxxflags=\"$CXXFLAGS\"                       # flags to use pthread and code optimization\n  ${FFMPEG_ST:+ --disable-multithread}\n)\n\nemconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j\n# Fix ffmpeg configure error: \"libvpx enabled but no supported decoders found\"\nemranlib $INSTALL_DIR/lib/libvpx.a\n"
  },
  {
    "path": "build/libwebp.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCM_FLAGS=(\n  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR\n  -DCMAKE_TOOLCHAIN_FILE=$EM_TOOLCHAIN_FILE\n  -DBUILD_SHARED_LIBS=OFF\n  -DZLIB_LIBRARY=$INSTALL_DIR/lib\n  -DZLIB_INCLUDE_DIR=$INSTALL_DIR/include\n  -DWEBP_ENABLE_SIMD=ON\n  -DWEBP_BUILD_ANIM_UTILS=OFF\n  -DWEBP_BUILD_CWEBP=OFF\n  -DWEBP_BUILD_DWEBP=OFF\n  -DWEBP_BUILD_GIF2WEBP=OFF\n  -DWEBP_BUILD_IMG2WEBP=OFF\n  -DWEBP_BUILD_VWEBP=OFF\n  -DWEBP_BUILD_WEBPINFO=OFF\n  -DWEBP_BUILD_WEBPMUX=OFF\n  -DWEBP_BUILD_EXTRAS=OFF\n)\n\nmkdir -p build\ncd build\nemmake cmake .. -DCMAKE_C_FLAGS=\"$CXXFLAGS\" ${CM_FLAGS[@]}\nemmake make install\n"
  },
  {
    "path": "build/ogg.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                                 # install library in a build directory for FFmpeg to include\n  --host=i686-linux                                   # use i686 linux\n  --disable-shared                                    # disable shared library\n  --disable-dependency-tracking                       # speed up one-time build\n  --disable-maintainer-mode\n)\n\nemconfigure ./autogen.sh\nemconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/opus.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=i686-none                                 # use i686 unknown\n  --enable-shared=no                                  # not to build shared library\n  --disable-asm                                       # not to use asm\n  --disable-rtcd                                      # not to detect cpu capabilities\n  --disable-intrinsics                                # not to use intrinsics\n  --disable-doc                                       # not to build docs\n  --disable-extra-programs                            # not to build demo and tests\n  --disable-stack-protector\n)\n\nemconfigure ./autogen.sh\nCFLAGS=$CFLAGS emconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/theora.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=i686-linux                                   # use i686 linux\n  --enable-shared=no                                  # disable shared library\n  --enable-docs=no\n  --enable-fast-install=no\n  --disable-spec\n  --disable-asm\n  --disable-examples\n  --disable-oggtest                                   # disable ogg tests\n  --disable-vorbistest                                # disable vorbis tests\n  --disable-sdltest                                   # disable sdl tests\n)\n\nemconfigure ./autogen.sh \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/vorbis.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\n# Remove this flag as clang doesn't recognize\nsed -i 's#-mno-ieee-fp##g' configure.ac\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                               # install library in a build directory for FFmpeg to include\n  --host=i686-linux                                   # use i686 linux\n  --enable-shared=no                                  # disable shared library\n  --enable-docs=no\n  --enable-examples=no\n  --enable-fast-install=no\n  --disable-oggtest                                   # disable oggtests\n  --disable-dependency-tracking                       # speed up one-time build\n)\n\nemconfigure ./autogen.sh \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/wavpack.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR                                # install library in a build directory for FFmpeg to include\n  --host=x86-linux-gnu                                 # use x86 linux as host\n  --disable-asm                                        # disable asm optimization\n  --disable-man                                        # disable docs\n  --disable-tests                                      # disable tests\n  --disable-apps                                       # disable wavpack apps\n  --disable-dsd                                        # disalbe legacy\n  --enable-legacy                                      # enable compability for old version of wav\n  --disable-shared                                     # enable building static library\n  --disable-dependency-tracking                        # speed up one-time build\n  --disable-maintainer-mode\n)\nCFLAGS=$CFLAGS emconfigure ./autogen.sh \"${CONF_FLAGS[@]}\"\nemmake make install -j\n"
  },
  {
    "path": "build/x264.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR           # lib installation dir\n  --host=x86-gnu                  # use x86 linux host\n  --enable-static                 # build static library\n  --disable-cli                   # disable cli build\n  --disable-asm                   # disable assembly\n  --extra-cflags=\"$CFLAGS\"        # add extra cflags\n  ${FFMPEG_ST:+ --disable-thread} # disable thread when FFMPEG_ST is defined\n)\n\nemconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install-lib-static -j\n"
  },
  {
    "path": "build/x265.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nBASE_FLAGS=(\n  -DCMAKE_TOOLCHAIN_FILE=$EM_TOOLCHAIN_FILE\n  -DENABLE_LIBNUMA=OFF\n  -DENABLE_SHARED=OFF\n  -DENABLE_CLI=OFF\n)\n\nFLAGS_12BIT=(\n  ${BASE_FLAGS[@]}\n  -DHIGH_BIT_DEPTH=ON\n  -DEXPORT_C_API=OFF\n  -DMAIN12=ON\n)\n\nFLAGS_10BIT=(\n  ${BASE_FLAGS[@]}\n  -DHIGH_BIT_DEPTH=ON\n  -DEXPORT_C_API=OFF\n)\n\nFLAGS_MAIN=(\n  ${BASE_FLAGS[@]}\n  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR\n  -DEXTRA_LIB=\"x265_main10.a;x265_main12.a\"\n  -DEXTRA_LINK_FLAGS=-L.\n  -DLINKED_10BIT=ON\n  -DLINKED_12BIT=ON\n)\n\ncd source\nrm -rf build\nmkdir -p build\ncd build\nmkdir -p main 10bit 12bit\n\ncd 12bit\nemmake cmake ../.. -DCMAKE_CXX_FLAGS=\"$CXXFLAGS\" ${FLAGS_12BIT[@]}\nemmake make -j\n\ncd ../10bit \nemmake cmake ../.. -DCMAKE_CXX_FLAGS=\"$CXXFLAGS\" ${FLAGS_10BIT[@]}\nemmake make -j\n\ncd ../main\nln -sf ../10bit/libx265.a libx265_main10.a\nln -sf ../12bit/libx265.a libx265_main12.a\nemmake cmake ../.. -DCMAKE_CXX_FLAGS=\"$CXXFLAGS\" ${FLAGS_MAIN[@]}\nemmake make -j\nmv libx265.a libx265_main.a\n\n# Merge static libraries\nemar -M <<EOF\nCREATE libx265.a\nADDLIB libx265_main.a\nADDLIB libx265_main10.a\nADDLIB libx265_main12.a\nSAVE\nEND\nEOF\nemmake make install -j\n"
  },
  {
    "path": "build/zimg.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCONF_FLAGS=(\n  --prefix=$INSTALL_DIR            # lib installation directory\n  --host=x86_64-linux-gnu          # use i686 linux host\n  --disable-shared                 # build static library\n  --enable-static                  # enable static library\n  --disable-dependency-tracking    # speed up one-time build\n  --disable-simd                   # disable simd optimization\n)\n\nemconfigure ./autogen.sh\n\nemconfigure ./configure \"${CONF_FLAGS[@]}\"\nemmake make install -j"
  },
  {
    "path": "build/zlib.sh",
    "content": "#!/bin/bash\n\nset -euo pipefail\n\nCM_FLAGS=(\n  -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR\n  -DCMAKE_TOOLCHAIN_FILE=$EM_TOOLCHAIN_FILE\n  -DBUILD_SHARED_LIBS=OFF\n  -DSKIP_INSTALL_FILES=ON\n)\n\nmkdir -p build\ncd build\nemmake cmake .. -DCMAKE_C_FLAGS=\"$CXXFLAGS\" ${CM_FLAGS[@]}\nemmake make clean\nemmake make install\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"root\",\n  \"private\": true,\n  \"scripts\": {\n    \"lint\": \"npm-run-all lint:*\",\n    \"lint:packages\": \"npm run lint --workspace=packages --if-present\",\n    \"lint:root\": \"eslint tests\",\n    \"build\": \"npm run build --workspace=packages --if-present\",\n    \"pretest\": \"npm run build\",\n    \"serve\": \"http-server -c-1 -s -p 3000 . --cors --headers '{\\\"Cross-Origin-Embedder-Policy\\\":\\\"require-corp\\\",\\\"Cross-Origin-Opener-Policy\\\":\\\"same-origin\\\",\\\"Cross-Origin-Resource-Policy\\\":\\\"cross-origin\\\",\\\"Origin-Agent-Cluster\\\":\\\"?1\\\"}'\",\n    \"test\": \"server-test test:browser:server 3000 test:all\",\n    \"test:all\": \"npm-run-all test:browser:*:*\",\n    \"test:browser\": \"mocha-headless-chrome -a enable-features=SharedArrayBuffer\",\n    \"test:browser:core:mt\": \"npm run test:browser -- -f http://localhost:3000/tests/ffmpeg-core-mt.test.html\",\n    \"test:browser:core:st\": \"npm run test:browser -- -f http://localhost:3000/tests/ffmpeg-core-st.test.html\",\n    \"test:browser:ffmpeg:mt\": \"npm run test:browser -- -f http://localhost:3000/tests/ffmpeg-mt.test.html\",\n    \"test:browser:ffmpeg:st\": \"npm run test:browser -- -f http://localhost:3000/tests/ffmpeg-st.test.html\",\n    \"test:browser:server\": \"npm run serve\",\n    \"test:node\": \"mocha --exit --bail -t 60000\",\n    \"test:node:core:mt\": \"npm run test:node -- --require tests/test-helper-mt.js tests/ffmpeg-core.test.js\",\n    \"test:node:core:st\": \"npm run test:node -- --require tests/test-helper-st.js tests/ffmpeg-core.test.js\",\n    \"prepublishOnly\": \"npm run build\",\n    \"postinstall\": \"npm run build\"\n  },\n  \"workspaces\": [\n    \"packages/*\",\n    \"apps/*\"\n  ],\n  \"devDependencies\": {\n    \"chai\": \"^4.3.7\",\n    \"http-server\": \"^14.1.1\",\n    \"mocha\": \"^10.2.0\",\n    \"mocha-headless-chrome\": \"^4.0.0\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"start-server-and-test\": \"^2.0.3\"\n  }\n}\n"
  },
  {
    "path": "packages/core/.gitignore",
    "content": "dist/\ntypes/\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@ffmpeg/core\",\n  \"version\": \"0.12.10\",\n  \"description\": \"FFmpeg WebAssembly version (single thread)\",\n  \"main\": \"./dist/umd/ffmpeg-core.js\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/esm/ffmpeg-core.js\",\n      \"require\": \"./dist/umd/ffmpeg-core.js\"\n    },\n    \"./wasm\": {\n      \"import\": \"./dist/esm/ffmpeg-core.wasm\",\n      \"require\": \"./dist/umd/ffmpeg-core.wasm\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git\"\n  },\n  \"keywords\": [\n    \"ffmpeg\",\n    \"WebAssembly\",\n    \"video\",\n    \"audio\",\n    \"transcode\"\n  ],\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"GPL-2.0-or-later\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ffmpegwasm/ffmpeg.wasm/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=16.x\"\n  },\n  \"homepage\": \"https://github.com/ffmpegwasm/ffmpeg.wasm#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/core-mt/.gitignore",
    "content": "dist/\ntypes/\n"
  },
  {
    "path": "packages/core-mt/package.json",
    "content": "{\n  \"name\": \"@ffmpeg/core-mt\",\n  \"version\": \"0.12.10\",\n  \"description\": \"FFmpeg WebAssembly version (multi thread)\",\n  \"main\": \"./dist/umd/ffmpeg-core.js\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/esm/ffmpeg-core.js\",\n      \"require\": \"./dist/umd/ffmpeg-core.js\"\n    },\n    \"./wasm\": {\n      \"import\": \"./dist/esm/ffmpeg-core.wasm\",\n      \"require\": \"./dist/umd/ffmpeg-core.wasm\"\n    },\n    \"./worker\": {\n      \"import\": \"./dist/esm/ffmpeg-core.worker.js\",\n      \"require\": \"./dist/umd/ffmpeg-core.worker.js\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git\"\n  },\n  \"keywords\": [\n    \"ffmpeg\",\n    \"WebAssembly\",\n    \"video\",\n    \"audio\",\n    \"transcode\"\n  ],\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"GPL-2.0-or-later\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ffmpegwasm/ffmpeg.wasm/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=16.x\"\n  },\n  \"homepage\": \"https://github.com/ffmpegwasm/ffmpeg.wasm#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/ffmpeg/.eslintignore",
    "content": ".eslintrc.cjs\n"
  },
  {
    "path": "packages/ffmpeg/.eslintrc.cjs",
    "content": "module.exports = {\n  extends: [\n    \"eslint:recommended\",\n    \"plugin:@typescript-eslint/recommended\",\n    \"plugin:@typescript-eslint/recommended-requiring-type-checking\",\n  ],\n  parser: \"@typescript-eslint/parser\",\n  parserOptions: {\n    tsconfigRootDir: __dirname,\n    project: [\"./tsconfig.json\", \"./src/worker/tsconfig.json\"],\n  },\n  plugins: [\"@typescript-eslint\"],\n};\n"
  },
  {
    "path": "packages/ffmpeg/.gitignore",
    "content": "dist/\ndocs/\n"
  },
  {
    "path": "packages/ffmpeg/package.json",
    "content": "{\n  \"name\": \"@ffmpeg/ffmpeg\",\n  \"version\": \"0.12.15\",\n  \"description\": \"FFmpeg WebAssembly version for browser\",\n  \"main\": \"./dist/umd/ffmpeg.js\",\n  \"types\": \"./dist/esm/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/esm/index.d.ts\",\n      \"node\": \"./dist/esm/empty.mjs\",\n      \"default\": {\n        \"import\": \"./dist/esm/index.js\",\n        \"require\": \"./dist/umd/ffmpeg.js\"\n      }\n    },\n    \"./worker\": {\n      \"types\": \"./dist/esm/worker.d.ts\",\n      \"default\": \"./dist/esm/worker.js\"\n    }\n  },\n  \"scripts\": {\n    \"dev\": \"webpack -w --mode development\",\n    \"lint\": \"eslint src\",\n    \"clean\": \"rimraf dist\",\n    \"build:esm\": \"tsc -p tsconfig.esm.json\",\n    \"build:umd\": \"webpack\",\n    \"build\": \"npm run clean && npm run build:esm && npm run build:umd\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\",\n    \"types/ffmpeg.d.ts\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git\"\n  },\n  \"keywords\": [\n    \"ffmpeg\",\n    \"WebAssembly\",\n    \"video\",\n    \"audio\",\n    \"transcode\"\n  ],\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ffmpegwasm/ffmpeg.wasm/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=18.x\"\n  },\n  \"homepage\": \"https://github.com/ffmpegwasm/ffmpeg.wasm#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"devDependencies\": {\n    \"@typescript-eslint/eslint-plugin\": \"^6.1.0\",\n    \"@typescript-eslint/parser\": \"^6.1.0\",\n    \"eslint\": \"^8.45.0\",\n    \"rimraf\": \"^5.0.1\",\n    \"typescript\": \"^5.1.6\",\n    \"webpack-cli\": \"^5.1.4\"\n  },\n  \"dependencies\": {\n    \"@ffmpeg/types\": \"^0.12.4\"\n  }\n}\n"
  },
  {
    "path": "packages/ffmpeg/src/classes.ts",
    "content": "import { FFMessageType } from \"./const.js\";\nimport {\n  CallbackData,\n  Callbacks,\n  FSNode,\n  FFMessageEventCallback,\n  FFMessageLoadConfig,\n  OK,\n  IsFirst,\n  LogEvent,\n  Message,\n  ProgressEvent,\n  LogEventCallback,\n  ProgressEventCallback,\n  FileData,\n  FFFSType,\n  FFFSMountOptions,\n  FFFSPath,\n} from \"./types.js\";\nimport { getMessageID } from \"./utils.js\";\nimport { ERROR_TERMINATED, ERROR_NOT_LOADED } from \"./errors.js\";\n\ntype FFMessageOptions = {\n  signal?: AbortSignal;\n};\n\n/**\n * Provides APIs to interact with ffmpeg web worker.\n *\n * @example\n * ```ts\n * const ffmpeg = new FFmpeg();\n * ```\n */\nexport class FFmpeg {\n  #worker: Worker | null = null;\n  /**\n   * #resolves and #rejects tracks Promise resolves and rejects to\n   * be called when we receive message from web worker.\n   */\n  #resolves: Callbacks = {};\n  #rejects: Callbacks = {};\n\n  #logEventCallbacks: LogEventCallback[] = [];\n  #progressEventCallbacks: ProgressEventCallback[] = [];\n\n  public loaded = false;\n\n  /**\n   * register worker message event handlers.\n   */\n  #registerHandlers = () => {\n    if (this.#worker) {\n      this.#worker.onmessage = ({\n        data: { id, type, data },\n      }: FFMessageEventCallback) => {\n        switch (type) {\n          case FFMessageType.LOAD:\n            this.loaded = true;\n            this.#resolves[id](data);\n            break;\n          case FFMessageType.MOUNT:\n          case FFMessageType.UNMOUNT:\n          case FFMessageType.EXEC:\n          case FFMessageType.FFPROBE:\n          case FFMessageType.WRITE_FILE:\n          case FFMessageType.READ_FILE:\n          case FFMessageType.DELETE_FILE:\n          case FFMessageType.RENAME:\n          case FFMessageType.CREATE_DIR:\n          case FFMessageType.LIST_DIR:\n          case FFMessageType.DELETE_DIR:\n            this.#resolves[id](data);\n            break;\n          case FFMessageType.LOG:\n            this.#logEventCallbacks.forEach((f) => f(data as LogEvent));\n            break;\n          case FFMessageType.PROGRESS:\n            this.#progressEventCallbacks.forEach((f) =>\n              f(data as ProgressEvent)\n            );\n            break;\n          case FFMessageType.ERROR:\n            this.#rejects[id](data);\n            break;\n        }\n        delete this.#resolves[id];\n        delete this.#rejects[id];\n      };\n    }\n  };\n\n  /**\n   * Generic function to send messages to web worker.\n   */\n  #send = (\n    { type, data }: Message,\n    trans: Transferable[] = [],\n    signal?: AbortSignal\n  ): Promise<CallbackData> => {\n    if (!this.#worker) {\n      return Promise.reject(ERROR_NOT_LOADED);\n    }\n\n    return new Promise((resolve, reject) => {\n      const id = getMessageID();\n      this.#worker && this.#worker.postMessage({ id, type, data }, trans);\n      this.#resolves[id] = resolve;\n      this.#rejects[id] = reject;\n\n      signal?.addEventListener(\n        \"abort\",\n        () => {\n          reject(new DOMException(`Message # ${id} was aborted`, \"AbortError\"));\n        },\n        { once: true }\n      );\n    });\n  };\n\n  /**\n   * Listen to log or progress events from `ffmpeg.exec()`.\n   *\n   * @example\n   * ```ts\n   * ffmpeg.on(\"log\", ({ type, message }) => {\n   *   // ...\n   * })\n   * ```\n   *\n   * @example\n   * ```ts\n   * ffmpeg.on(\"progress\", ({ progress, time }) => {\n   *   // ...\n   * })\n   * ```\n   *\n   * @remarks\n   * - log includes output to stdout and stderr.\n   * - The progress events are accurate only when the length of\n   * input and output video/audio file are the same.\n   *\n   * @category FFmpeg\n   */\n  public on(event: \"log\", callback: LogEventCallback): void;\n  public on(event: \"progress\", callback: ProgressEventCallback): void;\n  public on(\n    event: \"log\" | \"progress\",\n    callback: LogEventCallback | ProgressEventCallback\n  ) {\n    if (event === \"log\") {\n      this.#logEventCallbacks.push(callback as LogEventCallback);\n    } else if (event === \"progress\") {\n      this.#progressEventCallbacks.push(callback as ProgressEventCallback);\n    }\n  }\n\n  /**\n   * Unlisten to log or progress events from `ffmpeg.exec()`.\n   *\n   * @category FFmpeg\n   */\n  public off(event: \"log\", callback: LogEventCallback): void;\n  public off(event: \"progress\", callback: ProgressEventCallback): void;\n  public off(\n    event: \"log\" | \"progress\",\n    callback: LogEventCallback | ProgressEventCallback\n  ) {\n    if (event === \"log\") {\n      this.#logEventCallbacks = this.#logEventCallbacks.filter(\n        (f) => f !== callback\n      );\n    } else if (event === \"progress\") {\n      this.#progressEventCallbacks = this.#progressEventCallbacks.filter(\n        (f) => f !== callback\n      );\n    }\n  }\n\n  /**\n   * Loads ffmpeg-core inside web worker. It is required to call this method first\n   * as it initializes WebAssembly and other essential variables.\n   *\n   * @category FFmpeg\n   * @returns `true` if ffmpeg core is loaded for the first time.\n   */\n  public load = (\n    { classWorkerURL, ...config }: FFMessageLoadConfig = {},\n    { signal }: FFMessageOptions = {}\n  ): Promise<IsFirst> => {\n    if (!this.#worker) {\n      this.#worker = classWorkerURL ?\n        new Worker(new URL(classWorkerURL, import.meta.url), {\n          type: \"module\",\n        }) :\n        // We need to duplicated the code here to enable webpack\n        // to bundle worker.js here.\n        new Worker(new URL(\"./worker.js\", import.meta.url), {\n          type: \"module\",\n        });\n      this.#registerHandlers();\n    }\n    return this.#send(\n      {\n        type: FFMessageType.LOAD,\n        data: config,\n      },\n      undefined,\n      signal\n    ) as Promise<IsFirst>;\n  };\n\n  /**\n   * Execute ffmpeg command.\n   *\n   * @remarks\n   * To avoid common I/O issues, [\"-nostdin\", \"-y\"] are prepended to the args\n   * by default.\n   *\n   * @example\n   * ```ts\n   * const ffmpeg = new FFmpeg();\n   * await ffmpeg.load();\n   * await ffmpeg.writeFile(\"video.avi\", ...);\n   * // ffmpeg -i video.avi video.mp4\n   * await ffmpeg.exec([\"-i\", \"video.avi\", \"video.mp4\"]);\n   * const data = ffmpeg.readFile(\"video.mp4\");\n   * ```\n   *\n   * @returns `0` if no error, `!= 0` if timeout (1) or error.\n   * @category FFmpeg\n   */\n  public exec = (\n    /** ffmpeg command line args */\n    args: string[],\n    /**\n     * milliseconds to wait before stopping the command execution.\n     *\n     * @defaultValue -1\n     */\n    timeout = -1,\n    { signal }: FFMessageOptions = {}\n  ): Promise<number> =>\n    this.#send(\n      {\n        type: FFMessageType.EXEC,\n        data: { args, timeout },\n      },\n      undefined,\n      signal\n    ) as Promise<number>;\n\n  /**\n   * Execute ffprobe command.\n   *\n   * @example\n   * ```ts\n   * const ffmpeg = new FFmpeg();\n   * await ffmpeg.load();\n   * await ffmpeg.writeFile(\"video.avi\", ...);\n   * // Getting duration of a video in seconds: ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 video.avi -o output.txt\n   * await ffmpeg.ffprobe([\"-v\", \"error\", \"-show_entries\", \"format=duration\", \"-of\", \"default=noprint_wrappers=1:nokey=1\", \"video.avi\", \"-o\", \"output.txt\"]);\n   * const data = ffmpeg.readFile(\"output.txt\");\n   * ```\n   *\n   * @returns `0` if no error, `!= 0` if timeout (1) or error.\n   * @category FFmpeg\n   */\n  public ffprobe = (\n    /** ffprobe command line args */\n    args: string[],\n    /**\n     * milliseconds to wait before stopping the command execution.\n     *\n     * @defaultValue -1\n     */\n    timeout = -1,\n    { signal }: FFMessageOptions = {}\n  ): Promise<number> =>\n    this.#send(\n      {\n        type: FFMessageType.FFPROBE,\n        data: { args, timeout },\n      },\n      undefined,\n      signal\n    ) as Promise<number>;\n\n  /**\n   * Terminate all ongoing API calls and terminate web worker.\n   * `FFmpeg.load()` must be called again before calling any other APIs.\n   *\n   * @category FFmpeg\n   */\n  public terminate = (): void => {\n    const ids = Object.keys(this.#rejects);\n    // rejects all incomplete Promises.\n    for (const id of ids) {\n      this.#rejects[id](ERROR_TERMINATED);\n      delete this.#rejects[id];\n      delete this.#resolves[id];\n    }\n\n    if (this.#worker) {\n      this.#worker.terminate();\n      this.#worker = null;\n      this.loaded = false;\n    }\n  };\n\n  /**\n   * Write data to ffmpeg.wasm.\n   *\n   * @example\n   * ```ts\n   * const ffmpeg = new FFmpeg();\n   * await ffmpeg.load();\n   * await ffmpeg.writeFile(\"video.avi\", await fetchFile(\"../video.avi\"));\n   * await ffmpeg.writeFile(\"text.txt\", \"hello world\");\n   * ```\n   *\n   * @category File System\n   */\n  public writeFile = (\n    path: string,\n    data: FileData,\n    { signal }: FFMessageOptions = {}\n  ): Promise<OK> => {\n    const trans: Transferable[] = [];\n    if (data instanceof Uint8Array) {\n      trans.push(data.buffer);\n    }\n    return this.#send(\n      {\n        type: FFMessageType.WRITE_FILE,\n        data: { path, data },\n      },\n      trans,\n      signal\n    ) as Promise<OK>;\n  };\n\n  public mount = (fsType: FFFSType, options: FFFSMountOptions, mountPoint: FFFSPath, ): Promise<OK> => {\n    const trans: Transferable[] = [];\n    return this.#send(\n      {\n        type: FFMessageType.MOUNT,\n        data: { fsType, options, mountPoint },\n      },\n      trans\n    ) as Promise<OK>;\n  };\n\n  public unmount = (mountPoint: FFFSPath): Promise<OK> => {\n    const trans: Transferable[] = [];\n    return this.#send(\n      {\n        type: FFMessageType.UNMOUNT,\n        data: { mountPoint },\n      },\n      trans\n    ) as Promise<OK>;\n  };\n\n  /**\n   * Read data from ffmpeg.wasm.\n   *\n   * @example\n   * ```ts\n   * const ffmpeg = new FFmpeg();\n   * await ffmpeg.load();\n   * const data = await ffmpeg.readFile(\"video.mp4\");\n   * ```\n   *\n   * @category File System\n   */\n  public readFile = (\n    path: string,\n    /**\n     * File content encoding, supports two encodings:\n     * - utf8: read file as text file, return data in string type.\n     * - binary: read file as binary file, return data in Uint8Array type.\n     *\n     * @defaultValue binary\n     */\n    encoding = \"binary\",\n    { signal }: FFMessageOptions = {}\n  ): Promise<FileData> =>\n    this.#send(\n      {\n        type: FFMessageType.READ_FILE,\n        data: { path, encoding },\n      },\n      undefined,\n      signal\n    ) as Promise<FileData>;\n\n  /**\n   * Delete a file.\n   *\n   * @category File System\n   */\n  public deleteFile = (\n    path: string,\n    { signal }: FFMessageOptions = {}\n  ): Promise<OK> =>\n    this.#send(\n      {\n        type: FFMessageType.DELETE_FILE,\n        data: { path },\n      },\n      undefined,\n      signal\n    ) as Promise<OK>;\n\n  /**\n   * Rename a file or directory.\n   *\n   * @category File System\n   */\n  public rename = (\n    oldPath: string,\n    newPath: string,\n    { signal }: FFMessageOptions = {}\n  ): Promise<OK> =>\n    this.#send(\n      {\n        type: FFMessageType.RENAME,\n        data: { oldPath, newPath },\n      },\n      undefined,\n      signal\n    ) as Promise<OK>;\n\n  /**\n   * Create a directory.\n   *\n   * @category File System\n   */\n  public createDir = (\n    path: string,\n    { signal }: FFMessageOptions = {}\n  ): Promise<OK> =>\n    this.#send(\n      {\n        type: FFMessageType.CREATE_DIR,\n        data: { path },\n      },\n      undefined,\n      signal\n    ) as Promise<OK>;\n\n  /**\n   * List directory contents.\n   *\n   * @category File System\n   */\n  public listDir = (\n    path: string,\n    { signal }: FFMessageOptions = {}\n  ): Promise<FSNode[]> =>\n    this.#send(\n      {\n        type: FFMessageType.LIST_DIR,\n        data: { path },\n      },\n      undefined,\n      signal\n    ) as Promise<FSNode[]>;\n\n  /**\n   * Delete an empty directory.\n   *\n   * @category File System\n   */\n  public deleteDir = (\n    path: string,\n    { signal }: FFMessageOptions = {}\n  ): Promise<OK> =>\n    this.#send(\n      {\n        type: FFMessageType.DELETE_DIR,\n        data: { path },\n      },\n      undefined,\n      signal\n    ) as Promise<OK>;\n}\n"
  },
  {
    "path": "packages/ffmpeg/src/const.ts",
    "content": "export const MIME_TYPE_JAVASCRIPT = \"text/javascript\";\nexport const MIME_TYPE_WASM = \"application/wasm\";\n\nexport const CORE_VERSION = \"0.12.10\";\nexport const CORE_URL = `https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;\n\nexport enum FFMessageType {\n  LOAD = \"LOAD\",\n  EXEC = \"EXEC\",\n  FFPROBE = \"FFPROBE\",\n  WRITE_FILE = \"WRITE_FILE\",\n  READ_FILE = \"READ_FILE\",\n  DELETE_FILE = \"DELETE_FILE\",\n  RENAME = \"RENAME\",\n  CREATE_DIR = \"CREATE_DIR\",\n  LIST_DIR = \"LIST_DIR\",\n  DELETE_DIR = \"DELETE_DIR\",\n  ERROR = \"ERROR\",\n\n  DOWNLOAD = \"DOWNLOAD\",\n  PROGRESS = \"PROGRESS\",\n  LOG = \"LOG\",\n  MOUNT = \"MOUNT\",\n  UNMOUNT = \"UNMOUNT\",\n}\n"
  },
  {
    "path": "packages/ffmpeg/src/empty.mts",
    "content": "// File to be imported in node environments\n\nexport class FFmpeg {\n  constructor() {\n    throw new Error(\"ffmpeg.wasm does not support nodejs\");\n  }\n}"
  },
  {
    "path": "packages/ffmpeg/src/errors.ts",
    "content": "export const ERROR_UNKNOWN_MESSAGE_TYPE = new Error(\"unknown message type\");\nexport const ERROR_NOT_LOADED = new Error(\n  \"ffmpeg is not loaded, call `await ffmpeg.load()` first\"\n);\nexport const ERROR_TERMINATED = new Error(\"called FFmpeg.terminate()\");\nexport const ERROR_IMPORT_FAILURE = new Error(\n  \"failed to import ffmpeg-core.js\"\n);\n"
  },
  {
    "path": "packages/ffmpeg/src/index.ts",
    "content": "export * from \"./classes.js\";\nexport * from \"./types.js\";\nexport * from \"./const.js\";\n"
  },
  {
    "path": "packages/ffmpeg/src/types.ts",
    "content": "export type FFFSPath = string;\n\n/**\n * ffmpeg-core loading configuration.\n */\nexport interface FFMessageLoadConfig {\n  /**\n   * `ffmpeg-core.js` URL.\n   *\n   * @defaultValue `https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;\n   */\n  coreURL?: string;\n  /**\n   * `ffmpeg-core.wasm` URL.\n   *\n   * @defaultValue `https://cdn.jsdelivr.net/npm/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.wasm`;\n   */\n  wasmURL?: string;\n  /**\n   * `ffmpeg-core.worker.js` URL. This worker is spawned when using multithread version of ffmpeg-core.\n   *\n   * @ref: https://ffmpegwasm.netlify.app/docs/overview#architecture\n   * @defaultValue `https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.worker.js`;\n   */\n  workerURL?: string;\n  /**\n   * `ffmpeg.worker.js` URL. This worker is spawned when FFmpeg.load() is called, it is an essential worker and usually you don't need to update this config.\n   *\n   * @ref: https://ffmpegwasm.netlify.app/docs/overview#architecture\n   * @defaultValue `./worker.js`\n   */\n  classWorkerURL?: string;\n}\n\nexport interface FFMessageExecData {\n  args: string[];\n  timeout?: number;\n}\n\nexport interface FFMessageWriteFileData {\n  path: FFFSPath;\n  data: FileData;\n}\n\nexport interface FFMessageReadFileData {\n  path: FFFSPath;\n  encoding: string;\n}\n\nexport interface FFMessageDeleteFileData {\n  path: FFFSPath;\n}\n\nexport interface FFMessageRenameData {\n  oldPath: FFFSPath;\n  newPath: FFFSPath;\n}\n\nexport interface FFMessageCreateDirData {\n  path: FFFSPath;\n}\n\nexport interface FFMessageListDirData {\n  path: FFFSPath;\n}\n\n/**\n * @remarks\n * Only deletes empty directory.\n */\nexport interface FFMessageDeleteDirData {\n  path: FFFSPath;\n}\n\nexport enum FFFSType {\n  MEMFS = \"MEMFS\",\n  NODEFS = \"NODEFS\",\n  NODERAWFS = \"NODERAWFS\",\n  IDBFS  = \"IDBFS\",\n  WORKERFS = \"WORKERFS\",\n  PROXYFS = \"PROXYFS\",\n}\n\nexport type WorkerFSFileEntry =\n  | File;\n\nexport interface WorkerFSBlobEntry {\n  name: string;\n  data: Blob;\n}\n\nexport interface WorkerFSMountData {\n  blobs?: WorkerFSBlobEntry[];\n  files?: WorkerFSFileEntry[];\n}\n\nexport type FFFSMountOptions =\n  | WorkerFSMountData;\n\nexport interface FFMessageMountData {\n  fsType: FFFSType;\n  options: FFFSMountOptions;\n  mountPoint: FFFSPath;\n}\n\nexport interface FFMessageUnmountData {\n  mountPoint: FFFSPath;\n}\n\nexport type FFMessageData =\n  | FFMessageLoadConfig\n  | FFMessageExecData\n  | FFMessageWriteFileData\n  | FFMessageReadFileData\n  | FFMessageDeleteFileData\n  | FFMessageRenameData\n  | FFMessageCreateDirData\n  | FFMessageListDirData\n  | FFMessageDeleteDirData\n  | FFMessageMountData\n  | FFMessageUnmountData;\n\nexport interface Message {\n  type: string;\n  data?: FFMessageData;\n}\n\nexport interface FFMessage extends Message {\n  id: number;\n}\n\nexport interface FFMessageEvent extends MessageEvent {\n  data: FFMessage;\n}\n\nexport interface LogEvent {\n  type: string;\n  message: string;\n}\n\nexport interface ProgressEvent {\n  progress: number;\n  time: number;\n}\n\nexport type ExitCode = number;\nexport type ErrorMessage = string;\nexport type FileData = Uint8Array | string;\nexport type IsFirst = boolean;\nexport type OK = boolean;\n\nexport interface FSNode {\n  name: string;\n  isDir: boolean;\n}\n\nexport type CallbackData =\n  | FileData\n  | ExitCode\n  | ErrorMessage\n  | LogEvent\n  | ProgressEvent\n  | IsFirst\n  | OK // eslint-disable-line\n  | Error\n  | FSNode[]\n  | undefined;\n\nexport interface Callbacks {\n  [id: number | string]: (data: CallbackData) => void;\n}\n\nexport type LogEventCallback = (event: LogEvent) => void;\nexport type ProgressEventCallback = (event: ProgressEvent) => void;\n\nexport interface FFMessageEventCallback {\n  data: {\n    id: number;\n    type: string;\n    data: CallbackData;\n  };\n}\n"
  },
  {
    "path": "packages/ffmpeg/src/utils.ts",
    "content": "/**\n * Generate an unique message ID.\n */\nexport const getMessageID = (() => {\n  let messageID = 0;\n  return () => messageID++;\n})();\n"
  },
  {
    "path": "packages/ffmpeg/src/worker.ts",
    "content": "/// <reference no-default-lib=\"true\" />\n/// <reference lib=\"esnext\" />\n/// <reference lib=\"webworker\" />\n\nimport type { FFmpegCoreModule, FFmpegCoreModuleFactory } from \"@ffmpeg/types\";\nimport type {\n  FFMessageEvent,\n  FFMessageLoadConfig,\n  FFMessageExecData,\n  FFMessageWriteFileData,\n  FFMessageReadFileData,\n  FFMessageDeleteFileData,\n  FFMessageRenameData,\n  FFMessageCreateDirData,\n  FFMessageListDirData,\n  FFMessageDeleteDirData,\n  FFMessageMountData,\n  FFMessageUnmountData,\n  CallbackData,\n  IsFirst,\n  OK,\n  ExitCode,\n  FSNode,\n  FileData,\n} from \"./types\";\nimport { CORE_URL, FFMessageType } from \"./const.js\";\nimport {\n  ERROR_UNKNOWN_MESSAGE_TYPE,\n  ERROR_NOT_LOADED,\n  ERROR_IMPORT_FAILURE,\n} from \"./errors.js\";\n\ndeclare global {\n  interface WorkerGlobalScope {\n    createFFmpegCore: FFmpegCoreModuleFactory;\n  }\n}\n\ninterface ImportedFFmpegCoreModuleFactory {\n  default: FFmpegCoreModuleFactory;\n}\n\nlet ffmpeg: FFmpegCoreModule;\n\nconst load = async ({\n  coreURL: _coreURL,\n  wasmURL: _wasmURL,\n  workerURL: _workerURL,\n}: FFMessageLoadConfig): Promise<IsFirst> => {\n  const first = !ffmpeg;\n\n  try {\n    if (!_coreURL) _coreURL = CORE_URL;\n    // when web worker type is `classic`.\n    importScripts(_coreURL);\n  } catch {\n    if (!_coreURL || _coreURL === CORE_URL) _coreURL = CORE_URL.replace('/umd/', '/esm/');\n    // when web worker type is `module`.\n    (self as WorkerGlobalScope).createFFmpegCore = (\n      (await import(\n        /* @vite-ignore */ _coreURL\n      )) as ImportedFFmpegCoreModuleFactory\n    ).default;\n\n    if (!(self as WorkerGlobalScope).createFFmpegCore) {\n      throw ERROR_IMPORT_FAILURE;\n    }\n  }\n\n  const coreURL = _coreURL;\n  const wasmURL = _wasmURL ? _wasmURL : _coreURL.replace(/.js$/g, \".wasm\");\n  const workerURL = _workerURL\n    ? _workerURL\n    : _coreURL.replace(/.js$/g, \".worker.js\");\n\n  ffmpeg = await (self as WorkerGlobalScope).createFFmpegCore({\n    // Fix `Overload resolution failed.` when using multi-threaded ffmpeg-core.\n    // Encoded wasmURL and workerURL in the URL as a hack to fix locateFile issue.\n    mainScriptUrlOrBlob: `${coreURL}#${btoa(\n      JSON.stringify({ wasmURL, workerURL })\n    )}`,\n  });\n  ffmpeg.setLogger((data) =>\n    self.postMessage({ type: FFMessageType.LOG, data })\n  );\n  ffmpeg.setProgress((data) =>\n    self.postMessage({\n      type: FFMessageType.PROGRESS,\n      data,\n    })\n  );\n  return first;\n};\n\nconst exec = ({ args, timeout = -1 }: FFMessageExecData): ExitCode => {\n  ffmpeg.setTimeout(timeout);\n  ffmpeg.exec(...args);\n  const ret = ffmpeg.ret;\n  ffmpeg.reset();\n  return ret;\n};\n\nconst ffprobe = ({ args, timeout = -1 }: FFMessageExecData): ExitCode => {\n  ffmpeg.setTimeout(timeout);\n  ffmpeg.ffprobe(...args);\n  const ret = ffmpeg.ret;\n  ffmpeg.reset();\n  return ret;\n};\n\nconst writeFile = ({ path, data }: FFMessageWriteFileData): OK => {\n  ffmpeg.FS.writeFile(path, data);\n  return true;\n};\n\nconst readFile = ({ path, encoding }: FFMessageReadFileData): FileData =>\n  ffmpeg.FS.readFile(path, { encoding });\n\n// TODO: check if deletion works.\nconst deleteFile = ({ path }: FFMessageDeleteFileData): OK => {\n  ffmpeg.FS.unlink(path);\n  return true;\n};\n\nconst rename = ({ oldPath, newPath }: FFMessageRenameData): OK => {\n  ffmpeg.FS.rename(oldPath, newPath);\n  return true;\n};\n\n// TODO: check if creation works.\nconst createDir = ({ path }: FFMessageCreateDirData): OK => {\n  ffmpeg.FS.mkdir(path);\n  return true;\n};\n\nconst listDir = ({ path }: FFMessageListDirData): FSNode[] => {\n  const names = ffmpeg.FS.readdir(path);\n  const nodes: FSNode[] = [];\n  for (const name of names) {\n    const stat = ffmpeg.FS.stat(`${path}/${name}`);\n    const isDir = ffmpeg.FS.isDir(stat.mode);\n    nodes.push({ name, isDir });\n  }\n  return nodes;\n};\n\n// TODO: check if deletion works.\nconst deleteDir = ({ path }: FFMessageDeleteDirData): OK => {\n  ffmpeg.FS.rmdir(path);\n  return true;\n};\n\nconst mount = ({ fsType, options, mountPoint }: FFMessageMountData): OK => {\n  const str = fsType as keyof typeof ffmpeg.FS.filesystems;\n  const fs = ffmpeg.FS.filesystems[str];\n  if (!fs) return false;\n  ffmpeg.FS.mount(fs, options, mountPoint);\n  return true;\n};\n\nconst unmount = ({ mountPoint }: FFMessageUnmountData): OK => {\n  ffmpeg.FS.unmount(mountPoint);\n  return true;\n};\n\nself.onmessage = async ({\n  data: { id, type, data: _data },\n}: FFMessageEvent): Promise<void> => {\n  const trans = [];\n  let data: CallbackData;\n  try {\n    if (type !== FFMessageType.LOAD && !ffmpeg) throw ERROR_NOT_LOADED; // eslint-disable-line\n\n    switch (type) {\n      case FFMessageType.LOAD:\n        data = await load(_data as FFMessageLoadConfig);\n        break;\n      case FFMessageType.EXEC:\n        data = exec(_data as FFMessageExecData);\n        break;\n      case FFMessageType.FFPROBE:\n        data = ffprobe(_data as FFMessageExecData);\n        break;\n      case FFMessageType.WRITE_FILE:\n        data = writeFile(_data as FFMessageWriteFileData);\n        break;\n      case FFMessageType.READ_FILE:\n        data = readFile(_data as FFMessageReadFileData);\n        break;\n      case FFMessageType.DELETE_FILE:\n        data = deleteFile(_data as FFMessageDeleteFileData);\n        break;\n      case FFMessageType.RENAME:\n        data = rename(_data as FFMessageRenameData);\n        break;\n      case FFMessageType.CREATE_DIR:\n        data = createDir(_data as FFMessageCreateDirData);\n        break;\n      case FFMessageType.LIST_DIR:\n        data = listDir(_data as FFMessageListDirData);\n        break;\n      case FFMessageType.DELETE_DIR:\n        data = deleteDir(_data as FFMessageDeleteDirData);\n        break;\n      case FFMessageType.MOUNT:\n        data = mount(_data as FFMessageMountData);\n        break;\n      case FFMessageType.UNMOUNT:\n        data = unmount(_data as FFMessageUnmountData);\n        break;\n      default:\n        throw ERROR_UNKNOWN_MESSAGE_TYPE;\n    }\n  } catch (e) {\n    self.postMessage({\n      id,\n      type: FFMessageType.ERROR,\n      data: (e as Error).toString(),\n    });\n    return;\n  }\n  if (data instanceof Uint8Array) {\n    trans.push(data.buffer);\n  }\n  self.postMessage({ id, type, data }, trans);\n};\n"
  },
  {
    "path": "packages/ffmpeg/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"declaration\": true,\n    \"outDir\": \"./dist/esm\",\n    \"target\": \"esnext\",\n    \"moduleResolution\": \"nodenext\"\n  }\n}\n"
  },
  {
    "path": "packages/ffmpeg/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"esnext\",\n    \"rootDir\": \"src\"\n  }\n}\n"
  },
  {
    "path": "packages/ffmpeg/webpack.config.js",
    "content": "const path = require(\"path\");\n\nmodule.exports = {\n  mode: \"production\",\n  devtool: \"source-map\",\n  entry: \"./dist/esm/index.js\",\n  resolve: {\n    extensions: [\".js\"],\n  },\n  output: {\n    path: path.resolve(__dirname, \"dist/umd\"),\n    filename: \"ffmpeg.js\",\n    library: \"FFmpegWASM\",\n    libraryTarget: \"umd\",\n  },\n  stats: {\n    warnings:false\n  }\n};\n"
  },
  {
    "path": "packages/types/package.json",
    "content": "{\n  \"name\": \"@ffmpeg/types\",\n  \"version\": \"0.12.4\",\n  \"description\": \"ffmpeg.wasm types\",\n  \"types\": \"types\",\n  \"files\": [\n    \"types\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git\"\n  },\n  \"keywords\": [\n    \"ffmpeg\",\n    \"WebAssembly\",\n    \"video\",\n    \"audio\",\n    \"transcode\"\n  ],\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ffmpegwasm/ffmpeg.wasm/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=16.x\"\n  },\n  \"homepage\": \"https://github.com/ffmpegwasm/ffmpeg.wasm#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/types/types/index.d.ts",
    "content": "// TODO: Add lint and test.\n\nexport type Pointer = number;\n\nexport type StringPointer = Pointer;\nexport type StringArrayPointer = Pointer;\nexport type DateString = string;\n\n/**\n * Options for readFile.\n *\n * @see [Emscripten File System API](https://emscripten.org/docs/api_reference/Filesystem-API.html#FS.readFile)\n * @category File System\n */\nexport interface ReadFileOptions {\n  /** encoding of the file, must be `binary` or `utf8` */\n  encoding: string;\n}\n\n/**\n * Describes attributes of a node. (a.k.a file, directory)\n *\n * @see [Emscripten File System API](https://emscripten.org/docs/api_reference/Filesystem-API.html#FS.stat)\n * @category File System\n */\nexport interface Stat {\n  dev: number;\n  ino: number;\n  mode: number;\n  nlink: number;\n  uid: number;\n  gid: number;\n  rdev: number;\n  size: number;\n  atime: DateString;\n  mtime: DateString;\n  ctime: DateString;\n  blksize: number;\n  blocks: number;\n}\n\nexport interface FSFilesystemWORKERFS {}\n\nexport interface FSFilesystemMEMFS {}\n\nexport interface FSFilesystems {\n  WORKERFS: FSFilesystemWORKERFS;\n  MEMFS: FSFilesystemMEMFS;\n}\n\nexport type FSFilesystem = FSFilesystemWORKERFS | FSFilesystemMEMFS;\n\nexport interface OptionReadFile {\n  encoding: string;\n}\n\nexport interface WorkerFSMountConfig {\n  blobs?: {\n    name: string;\n    data: Blob;\n  }[];\n  files?: File[];\n}\n\n/**\n * Functions to interact with Emscripten FS library.\n *\n * @see [Emscripten File System API](https://emscripten.org/docs/api_reference/Filesystem-API.html)\n * @category File System\n */\nexport interface FS {\n  mkdir: (path: string) => void;\n  rmdir: (path: string) => void;\n  rename: (oldPath: string, newPath: string) => void;\n  writeFile: (path: string, data: Uint8Array | string) => void;\n  readFile: (path: string, opts: OptionReadFile) => Uint8Array | string;\n  readdir: (path: string) => string[];\n  unlink: (path: string) => void;\n  stat: (path: string) => Stat;\n  /** mode is a numeric notation of permission, @see [Numeric Notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) */\n  isFile: (mode: number) => boolean;\n  /** mode is a numeric notation of permission, @see [Numeric Notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) */\n  isDir: (mode: number) => boolean;\n  mount: (\n    fileSystemType: FSFilesystem,\n    data: WorkerFSMountConfig,\n    path: string\n  ) => void;\n  unmount: (path: string) => void;\n  filesystems: FSFilesystems;\n}\n\n/**\n * Arguments passed to setLogger callback function.\n */\nexport interface Log {\n  /** file descriptor of the log, must be `stdout` or `stderr` */\n  type: string;\n  message: string;\n}\n\n/**\n * Arguments passed to setProgress callback function.\n */\nexport interface Progress {\n  /** progress of the operation, interval = [0, 1] */\n  progress: number;\n  /** time of transcoded media in microseconds, ex: if a video is 10 seconds long, when time is 1000000 means 1 second of the video is transcoded already. */\n  time: number;\n}\n\n/**\n * FFmpeg core module, an object to interact with ffmpeg.\n */\nexport interface FFmpegCoreModule {\n  /** default arguments prepend when running exec() */\n  DEFAULT_ARGS: string[];\n  FS: FS;\n  NULL: Pointer;\n  SIZE_I32: number;\n\n  /** return code of the ffmpeg exec, error when ret != 0 */\n  ret: number;\n  timeout: number;\n  mainScriptUrlOrBlob: string;\n\n  exec: (...args: string[]) => number;\n  ffprobe: (...args: string[]) => number;\n  reset: () => void;\n  setLogger: (logger: (log: Log) => void) => void;\n  setTimeout: (timeout: number) => void;\n  setProgress: (handler: (progress: Progress) => void) => void;\n\n  locateFile: (path: string, prefix: string) => string;\n}\n\n/**\n * Factory of FFmpegCoreModule.\n */\nexport type FFmpegCoreModuleFactory = (\n  moduleOverrides?: Partial<FFmpegCoreModule>\n) => Promise<FFmpegCoreModule>;\n"
  },
  {
    "path": "packages/util/.eslintrc.cjs",
    "content": "module.exports = {\n  extends: [\n    \"eslint:recommended\",\n    \"plugin:@typescript-eslint/recommended\",\n    \"plugin:@typescript-eslint/recommended-requiring-type-checking\",\n  ],\n  parser: \"@typescript-eslint/parser\",\n  parserOptions: {\n    tsconfigRootDir: __dirname,\n    project: [\"./tsconfig.json\"],\n  },\n  plugins: [\"@typescript-eslint\"],\n};\n"
  },
  {
    "path": "packages/util/.gitignore",
    "content": "dist/\n"
  },
  {
    "path": "packages/util/package.json",
    "content": "{\n  \"name\": \"@ffmpeg/util\",\n  \"version\": \"0.12.2\",\n  \"description\": \"browser utils for @ffmpeg/*\",\n  \"main\": \"./dist/cjs/index.js\",\n  \"type\": \"module\",\n  \"types\": \"./dist/cjs/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/cjs/index.d.ts\",\n      \"import\": \"./dist/esm/index.js\",\n      \"require\": \"./dist/cjs/index.js\"\n    }\n  },\n  \"scripts\": {\n    \"dev\": \"tsc -p tsconfig-esm.json --watch\",\n    \"lint\": \"eslint src\",\n    \"clean\": \"rimraf dist\",\n    \"build:esm\": \"tsc -p tsconfig.esm.json\",\n    \"build:umd\": \"tsc -p tsconfig.cjs.json && webpack\",\n    \"build\": \"npm run clean && npm run build:esm && npm run build:umd\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git\"\n  },\n  \"keywords\": [\n    \"ffmpeg\",\n    \"video\",\n    \"audio\",\n    \"transcode\"\n  ],\n  \"author\": \"Jerome Wu <jeromewus@gmail.com>\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ffmpegwasm/ffmpeg.wasm/issues\"\n  },\n  \"engines\": {\n    \"node\": \">=18.x\"\n  },\n  \"homepage\": \"https://github.com/ffmpegwasm/ffmpeg.wasm#readme\",\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"devDependencies\": {\n    \"@typescript-eslint/eslint-plugin\": \"^6.1.0\",\n    \"@typescript-eslint/parser\": \"^6.1.0\",\n    \"eslint\": \"^8.45.0\",\n    \"rimraf\": \"^5.0.1\",\n    \"typescript\": \"^5.1.6\",\n    \"webpack-cli\": \"^5.1.4\"\n  }\n}\n"
  },
  {
    "path": "packages/util/src/const.ts",
    "content": "export const HeaderContentLength = \"Content-Length\";\n"
  },
  {
    "path": "packages/util/src/errors.ts",
    "content": "export const ERROR_RESPONSE_BODY_READER = new Error(\n  \"failed to get response body reader\"\n);\nexport const ERROR_INCOMPLETED_DOWNLOAD = new Error(\n  \"failed to complete download\"\n);\n"
  },
  {
    "path": "packages/util/src/index.ts",
    "content": "import {\n  ERROR_RESPONSE_BODY_READER,\n  ERROR_INCOMPLETED_DOWNLOAD,\n} from \"./errors.js\";\nimport { HeaderContentLength } from \"./const.js\";\nimport { ProgressCallback } from \"./types.js\";\n\nconst readFromBlobOrFile = (blob: Blob | File): Promise<Uint8Array> =>\n  new Promise((resolve, reject) => {\n    const fileReader = new FileReader();\n    fileReader.onload = () => {\n      const { result } = fileReader;\n      if (result instanceof ArrayBuffer) {\n        resolve(new Uint8Array(result));\n      } else {\n        resolve(new Uint8Array());\n      }\n    };\n    fileReader.onerror = (event) => {\n      reject(\n        Error(\n          `File could not be read! Code=${event?.target?.error?.code || -1}`\n        )\n      );\n    };\n    fileReader.readAsArrayBuffer(blob);\n  });\n\n/**\n * An util function to fetch data from url string, base64, URL, File or Blob format.\n *\n * Examples:\n * ```ts\n * // URL\n * await fetchFile(\"http://localhost:3000/video.mp4\");\n * // base64\n * await fetchFile(\"data:<type>;base64,wL2dvYWwgbW9yZ...\");\n * // URL\n * await fetchFile(new URL(\"video.mp4\", import.meta.url));\n * // File\n * fileInput.addEventListener('change', (e) => {\n *   await fetchFile(e.target.files[0]);\n * });\n * // Blob\n * const blob = new Blob(...);\n * await fetchFile(blob);\n * ```\n */\nexport const fetchFile = async (\n  file?: string | File | Blob\n): Promise<Uint8Array> => {\n  let data: ArrayBuffer | number[];\n\n  if (typeof file === \"string\") {\n    /* From base64 format */\n    if (/data:_data\\/([a-zA-Z]*);base64,([^\"]*)/.test(file)) {\n      data = atob(file.split(\",\")[1])\n        .split(\"\")\n        .map((c) => c.charCodeAt(0));\n      /* From remote server/URL */\n    } else {\n      data = await (await fetch(file)).arrayBuffer();\n    }\n  } else if (file instanceof URL) {\n    data = await (await fetch(file)).arrayBuffer();\n  } else if (file instanceof File || file instanceof Blob) {\n    data = await readFromBlobOrFile(file);\n  } else {\n    return new Uint8Array();\n  }\n\n  return new Uint8Array(data);\n};\n\n/**\n * importScript dynamically import a script, useful when you\n * want to use different versions of ffmpeg.wasm based on environment.\n *\n * Example:\n *\n * ```ts\n * await importScript(\"http://localhost:3000/ffmpeg.js\");\n * ```\n */\nexport const importScript = async (url: string): Promise<void> =>\n  new Promise((resolve) => {\n    const script = document.createElement(\"script\");\n    const eventHandler = () => {\n      script.removeEventListener(\"load\", eventHandler);\n      resolve();\n    };\n    script.src = url;\n    script.type = \"text/javascript\";\n    script.addEventListener(\"load\", eventHandler);\n    document.getElementsByTagName(\"head\")[0].appendChild(script);\n  });\n\n/**\n * Download content of a URL with progress.\n *\n * Progress only works when Content-Length is provided by the server.\n *\n */\nexport const downloadWithProgress = async (\n  url: string | URL,\n  cb?: ProgressCallback\n): Promise<ArrayBuffer> => {\n  const resp = await fetch(url);\n  const fallback = resp.clone();\n  let buf;\n\n  try {\n    // Set total to -1 to indicate that there is not Content-Type Header.\n    const total = parseInt(resp.headers.get(HeaderContentLength) || \"-1\");\n\n    const reader = resp.body?.getReader();\n    if (!reader) throw ERROR_RESPONSE_BODY_READER;\n\n    const chunks = [];\n    let received = 0;\n    for (;;) {\n      const { done, value } = await reader.read();\n      const delta = value ? value.length : 0;\n\n      if (done) {\n        if (total != -1 && total !== received) throw ERROR_INCOMPLETED_DOWNLOAD;\n        cb && cb({ url, total, received, delta, done });\n        break;\n      }\n\n      chunks.push(value);\n      received += delta;\n      cb && cb({ url, total, received, delta, done });\n    }\n\n    const data = new Uint8Array(received);\n    let position = 0;\n    for (const chunk of chunks) {\n      data.set(chunk, position);\n      position += chunk.length;\n    }\n\n    buf = data.buffer;\n  } catch (e) {\n    console.log(`failed to send download progress event: `, e);\n    // Fetch arrayBuffer directly when it is not possible to get progress.\n    buf = await fallback.arrayBuffer();\n    cb &&\n      cb({\n        url,\n        total: buf.byteLength,\n        received: buf.byteLength,\n        delta: 0,\n        done: true,\n      });\n  }\n\n  return buf;\n};\n\n/**\n * toBlobURL fetches data from an URL and return a blob URL.\n *\n * Example:\n *\n * ```ts\n * await toBlobURL(\"http://localhost:3000/ffmpeg.js\", \"text/javascript\");\n * ```\n */\nexport const toBlobURL = async (\n  url: string,\n  mimeType: string,\n  progress = false,\n  cb?: ProgressCallback\n): Promise<string> => {\n  const buf = progress\n    ? await downloadWithProgress(url, cb)\n    : await (await fetch(url)).arrayBuffer();\n  const blob = new Blob([buf], { type: mimeType });\n  return URL.createObjectURL(blob);\n};\n"
  },
  {
    "path": "packages/util/src/types.ts",
    "content": "export interface DownloadProgressEvent {\n  url: string | URL;\n  total: number;\n  received: number;\n  delta: number;\n  done: boolean;\n}\n\nexport type ProgressCallback = (event: DownloadProgressEvent) => void;\n"
  },
  {
    "path": "packages/util/tests/.eslintrc",
    "content": "{\n  \"rules\": {\n    \"no-undef\": 0,\n    \"camelcase\": 0\n  }\n}\n"
  },
  {
    "path": "packages/util/tests/constants.js",
    "content": "const TIMEOUT = 60000;\nconst IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';\nconst OPTIONS = {\n  corePath: IS_BROWSER ? 'http://localhost:3000/node_modules/@ffmpeg/core/dist/ffmpeg-core.js' : '@ffmpeg/core',\n};\nconst FLAME_MP4_LENGTH = 100374;\nconst META_FLAME_MP4_LENGTH = 100408;\nconst META_FLAME_MP4_LENGTH_NO_SPACE = 100404;\n\nif (typeof module !== 'undefined') {\n  module.exports = {\n    TIMEOUT,\n    IS_BROWSER,\n    OPTIONS,\n    FLAME_MP4_LENGTH,\n    META_FLAME_MP4_LENGTH,\n    META_FLAME_MP4_LENGTH_NO_SPACE,\n  };\n}\n"
  },
  {
    "path": "packages/util/tests/ffmpeg.test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>FFmpeg Unit Test</title>\n  <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\">\n</head>\n<body>\n  <div id=\"mocha\"></div>\n  <script src=\"../node_modules/mocha/mocha.js\"></script>\n  <script src=\"../node_modules/chai/chai.js\"></script>\n  <script src=\"../dist/ffmpeg.dev.js\"></script>\n  <script src=\"./constants.js\"></script>\n  <script>mocha.setup('bdd');</script>\n  <script src=\"./ffmpeg.test.js\"></script>\n  <script>\n    window.expect = chai.expect;\n    mocha.run();\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "packages/util/tests/ffmpeg.test.js",
    "content": "const { createFFmpeg } = FFmpeg;\n\ndescribe('FS()', () => {\n  const ffmpeg = createFFmpeg(OPTIONS);\n  before(async function cb() {\n    this.timeout(0);\n    await ffmpeg.load();\n  });\n\n  it('should throw error when readdir for invalid path ', () => {\n    expect(() => ffmpeg.FS('readdir', '/invalid')).to.throw(/readdir/);\n  });\n  it('should throw error when readFile for invalid path ', () => {\n    expect(() => ffmpeg.FS('readFile', '/invalid')).to.throw(/readFile/);\n  });\n  it('should throw an default error ', () => {\n    expect(() => ffmpeg.FS('unlink', '/invalid')).to.throw(/Oops/);\n  });\n});\n\ndescribe('load()', () => {\n  it('should throw error when corePath is not a string', async () => {\n    const ffmpeg = createFFmpeg({ ...OPTIONS, corePath: null });\n\n    try {\n      await ffmpeg.load();\n    } catch (e) {\n      expect(e).to.be.an('Error');\n    }\n  });\n  it('should throw error when not called before FS() and run()', () => {\n    const ffmpeg = createFFmpeg(OPTIONS);\n    expect(() => ffmpeg.FS('readdir', 'dummy')).to.throw();\n    expect(() => ffmpeg.run('-h')).to.throw();\n  });\n\n  it('should throw error when running load() more than once', async () => {\n    const ffmpeg = createFFmpeg(OPTIONS);\n    await ffmpeg.load();\n    try {\n      await ffmpeg.load();\n    } catch (e) {\n      expect(e).to.be.an('Error');\n    }\n  }).timeout(TIMEOUT);\n});\n\ndescribe('isLoaded()', () => {\n  it('should return true when loaded', async () => {\n    const ffmpeg = createFFmpeg(OPTIONS);\n    await ffmpeg.load();\n    expect(ffmpeg.isLoaded()).to.equal(true);\n  }).timeout(TIMEOUT);\n});\n\ndescribe('run()', () => {\n  it('should not allow to run two command at the same time', async () => {\n    const ffmpeg = createFFmpeg(OPTIONS);\n    await ffmpeg.load();\n    ffmpeg.run('-h');\n    setTimeout(() => {\n      try {\n        ffmpeg.run('-h');\n      } catch (e) {\n        expect(e).to.be.an(Error);\n      }\n    }, 500);\n  }).timeout(TIMEOUT);\n});\n"
  },
  {
    "path": "packages/util/tsconfig.cjs.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"compilerOptions\": {\n        \"module\": \"commonjs\",\n        \"outDir\": \"dist/cjs\",\n        \"target\": \"es2015\"\n    }\n}\n"
  },
  {
    "path": "packages/util/tsconfig.esm.json",
    "content": "{\n    \"extends\": \"./tsconfig.json\",\n    \"compilerOptions\": {\n        \"module\": \"esnext\",\n        \"outDir\": \"dist/esm\",\n        \"target\": \"esnext\",\n        \"moduleResolution\": \"nodenext\"\n    }\n}\n"
  },
  {
    "path": "packages/util/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"declaration\": true\n  }\n}\n"
  },
  {
    "path": "packages/util/webpack.config.cjs",
    "content": "const path = require(\"path\");\n\nmodule.exports = {\n  mode: \"production\",\n  entry: \"./dist/cjs/index.js\",\n  output: {\n    library: \"FFmpegUtil\",\n    libraryTarget: \"umd\",\n    filename: \"index.js\",\n    path: path.resolve(__dirname, \"dist\", \"umd\"),\n  },\n};\n"
  },
  {
    "path": "scripts/download-assets.js",
    "content": "const tar = require(\"tar\");\nconst fs = require(\"fs\");\n\nconst NPM_URL = \"https://registry.npmjs.org\";\nconst ROOT = \"public/assets\";\n\nconst FFMPEG_VERSION = \"0.12.15\";\nconst UTIL_VERSION = \"0.12.2\";\nconst CORE_VERSION = \"0.12.10\";\nconst CORE_MT_VERSION = \"0.12.10\";\n\nconst FFMPEG_TGZ = `ffmpeg-${FFMPEG_VERSION}.tgz`;\nconst UTIL_TGZ = `util-${UTIL_VERSION}.tgz`;\nconst CORE_TGZ = `core-${CORE_VERSION}.tgz`;\nconst CORE_MT_TGZ = `core-mt-${CORE_MT_VERSION}.tgz`;\n\nconst FFMPEG_TGZ_URL = `${NPM_URL}/@ffmpeg/ffmpeg/-/${FFMPEG_TGZ}`;\nconst UTIL_TGZ_URL = `${NPM_URL}/@ffmpeg/util/-/${UTIL_TGZ}`;\nconst CORE_TGZ_URL = `${NPM_URL}/@ffmpeg/core/-/${CORE_TGZ}`;\nconst CORE_MT_TGZ_URL = `${NPM_URL}/@ffmpeg/core-mt/-/${CORE_MT_TGZ}`;\n\nconst mkdir = (dir) => {\n  !fs.existsSync(dir) && fs.mkdirSync(dir);\n};\n\nconst downloadAndUntar = async (url, tgzName, dst) => {\n  const dir = `${ROOT}/${dst}`;\n  if (fs.existsSync(dir)) {\n    console.log(`found @ffmpeg/${dst} assets.`);\n    return;\n  }\n  console.log(`download and untar ${url}`);\n  mkdir(dir);\n  const data = Buffer.from(await (await fetch(url)).arrayBuffer());\n  fs.writeFileSync(tgzName, data);\n\n  await tar.x({ file: tgzName, C: `${ROOT}/${dst}` });\n  fs.unlinkSync(tgzName);\n};\n\nmkdir(ROOT);\ndownloadAndUntar(FFMPEG_TGZ_URL, FFMPEG_TGZ, \"ffmpeg\");\ndownloadAndUntar(UTIL_TGZ_URL, UTIL_TGZ, \"util\");\ndownloadAndUntar(CORE_TGZ_URL, CORE_TGZ, \"core\");\ndownloadAndUntar(CORE_MT_TGZ_URL, CORE_MT_TGZ, \"core-mt\");\n"
  },
  {
    "path": "src/bind/.eslintrc.cjs",
    "content": "module.exports = {\n  extends: \"eslint:recommended\",\n  rules: {\n    \"@typescript-eslint/no-empty-function\": 0,\n    \"@typescript-eslint/no-unsafe-assignment\": 0,\n    \"@typescript-eslint/restrict-plus-operands\": 0,\n    \"@typescript-eslint/no-unsafe-call\": 0,\n    \"@typescript-eslint/no-unsafe-return\": 0,\n    \"@typescript-eslint/no-unsafe-member-access\": 0,\n  },\n  globals: {\n    Module: true,\n    console: true,\n  },\n};\n"
  },
  {
    "path": "src/bind/ffmpeg/bind.js",
    "content": "/**\n * Constants\n */\n\nconst NULL = 0;\nconst SIZE_I32 = Uint32Array.BYTES_PER_ELEMENT;\nconst DEFAULT_ARGS = [\"./ffmpeg\", \"-nostdin\", \"-y\"];\nconst DEFAULT_ARGS_FFPROBE = [\"./ffprobe\"];\n\nModule[\"NULL\"] = NULL;\nModule[\"SIZE_I32\"] = SIZE_I32;\nModule[\"DEFAULT_ARGS\"] = DEFAULT_ARGS;\nModule[\"DEFAULT_ARGS_FFPROBE\"] = DEFAULT_ARGS_FFPROBE;\n\n/**\n * Variables\n */\n\nModule[\"ret\"] = -1;\nModule[\"timeout\"] = -1;\nModule[\"logger\"] = () => {};\nModule[\"progress\"] = () => {};\n\n/**\n * Functions\n */\n\nfunction stringToPtr(str) {\n  const len = Module[\"lengthBytesUTF8\"](str) + 1;\n  const ptr = Module[\"_malloc\"](len);\n  Module[\"stringToUTF8\"](str, ptr, len);\n\n  return ptr;\n}\n\nfunction stringsToPtr(strs) {\n  const len = strs.length;\n  const ptr = Module[\"_malloc\"](len * SIZE_I32);\n  for (let i = 0; i < len; i++) {\n    Module[\"setValue\"](ptr + SIZE_I32 * i, stringToPtr(strs[i]), \"i32\");\n  }\n\n  return ptr;\n}\n\nfunction print(message) {\n  Module[\"logger\"]({ type: \"stdout\", message });\n}\n\nfunction printErr(message) {\n  if (!message.startsWith(\"Aborted(native code called abort())\"))\n    Module[\"logger\"]({ type: \"stderr\", message });\n}\n\nfunction exec(..._args) {\n  const args = [...Module[\"DEFAULT_ARGS\"], ..._args];\n  try {\n    Module[\"_ffmpeg\"](args.length, stringsToPtr(args));\n  } catch (e) {\n    if (!e.message.startsWith(\"Aborted\")) {\n      throw e;\n    }\n  }\n  return Module[\"ret\"];\n}\n\nfunction ffprobe(..._args) {\n  const args = [...Module[\"DEFAULT_ARGS_FFPROBE\"], ..._args];\n  try {\n    Module[\"_ffprobe\"](args.length, stringsToPtr(args));\n  } catch (e) {\n    if (!e.message.startsWith(\"Aborted\")) {\n      throw e;\n    }\n  }\n  return Module[\"ret\"];\n}\n\nfunction setLogger(logger) {\n  Module[\"logger\"] = logger;\n}\n\nfunction setTimeout(timeout) {\n  Module[\"timeout\"] = timeout;\n}\n\nfunction setProgress(handler) {\n  Module[\"progress\"] = handler;\n}\n\nfunction receiveProgress(progress, time) {\n  Module[\"progress\"]({ progress, time });\n}\n\nfunction reset() {\n  Module[\"ret\"] = -1;\n  Module[\"timeout\"] = -1;\n}\n\n/**\n * In multithread version of ffmpeg.wasm, the bootstrap process is like:\n * 1. Execute ffmpeg-core.js\n * 2. ffmpeg-core.js spawns workers by calling `new Worker(\"ffmpeg-core.worker.js\")`\n * 3. ffmpeg-core.worker.js imports ffmpeg-core.js\n * 4. ffmpeg-core.js imports ffmpeg-core.wasm\n *\n * It is a straightforward process when all files are in the same location.\n * But when files are in different location (or Blob URL), #4 fails because\n * there is no way to pass custom ffmpeg-core.wasm URL to ffmpeg-core.worker.js\n * when it imports ffmpeg-core.js in #3.\n *\n * To fix this issue, a hack here is leveraging mainScriptUrlOrBlob variable by\n * adding wasmURL and workerURL in base64 format as query string. ex:\n *\n *   http://example.com/ffmpeg-core.js#{btoa(JSON.stringify({\"wasmURL\": \"...\", \"workerURL\": \"...\"}))}\n *\n * Thus, we can successfully extract custom URLs using _locateFile funciton.\n */\nfunction _locateFile(path, prefix) {\n  const mainScriptUrlOrBlob = Module[\"mainScriptUrlOrBlob\"];\n  if (mainScriptUrlOrBlob) {\n    const { wasmURL, workerURL } = JSON.parse(\n      atob(mainScriptUrlOrBlob.slice(mainScriptUrlOrBlob.lastIndexOf(\"#\") + 1))\n    );\n    if (path.endsWith(\".wasm\")) return wasmURL;\n    if (path.endsWith(\".worker.js\")) return workerURL;\n  }\n  return prefix + path;\n}\n\nModule[\"stringToPtr\"] = stringToPtr;\nModule[\"stringsToPtr\"] = stringsToPtr;\nModule[\"print\"] = print;\nModule[\"printErr\"] = printErr;\nModule[\"locateFile\"] = _locateFile;\n\nModule[\"exec\"] = exec;\nModule[\"ffprobe\"] = ffprobe;\nModule[\"setLogger\"] = setLogger;\nModule[\"setTimeout\"] = setTimeout;\nModule[\"setProgress\"] = setProgress;\nModule[\"reset\"] = reset;\nModule[\"receiveProgress\"] = receiveProgress;\n"
  },
  {
    "path": "src/bind/ffmpeg/export-runtime.js",
    "content": "const EXPORTED_RUNTIME_METHODS = [\n  \"FS\",\n  \"setValue\",\n  \"getValue\",\n  \"UTF8ToString\",\n  \"lengthBytesUTF8\",\n  \"stringToUTF8\",\n];\n\nconsole.log(EXPORTED_RUNTIME_METHODS.join(\",\"));\n"
  },
  {
    "path": "src/bind/ffmpeg/export.js",
    "content": "const EXPORTED_FUNCTIONS = [\"_ffmpeg\", \"_abort\", \"_malloc\", \"_ffprobe\"];\n\nconsole.log(EXPORTED_FUNCTIONS.join(\",\"));\n"
  },
  {
    "path": "src/fftools/Makefile",
    "content": "AVPROGS-$(CONFIG_FFMPEG)   += ffmpeg\nAVPROGS-$(CONFIG_FFPLAY)   += ffplay\nAVPROGS-$(CONFIG_FFPROBE)  += ffprobe\n\nAVPROGS     := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF))\nPROGS       += $(AVPROGS)\n\nAVBASENAMES  = ffmpeg ffplay ffprobe\nALLAVPROGS   = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))\nALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))\n\nOBJS-ffmpeg +=                  \\\n    fftools/ffmpeg_filter.o     \\\n    fftools/ffmpeg_hw.o         \\\n    fftools/ffmpeg_mux.o        \\\n    fftools/ffmpeg_opt.o        \\\n\ndefine DOFFTOOL\nOBJS-$(1) += fftools/cmdutils.o fftools/opt_common.o fftools/$(1).o $(OBJS-$(1)-yes)\n$(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))\n$$(OBJS-$(1)): | fftools\n$$(OBJS-$(1)): CFLAGS  += $(CFLAGS-$(1))\n$(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))\n$(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1))\n-include $$(OBJS-$(1):.o=.d)\nendef\n\n$(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P))))\n\nall: $(AVPROGS)\n\nfftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools\nOUTDIRS += fftools\n\nifdef AVPROGS\ninstall: install-progs install-data\nendif\n\ninstall-progs-yes:\ninstall-progs-$(CONFIG_SHARED): install-libs\n\ninstall-progs: install-progs-yes $(AVPROGS)\n\t$(Q)mkdir -p \"$(BINDIR)\"\n\t$(INSTALL) -c -m 755 $(AVPROGS) \"$(BINDIR)\"\n\nuninstall: uninstall-progs\n\nuninstall-progs:\n\t$(RM) $(addprefix \"$(BINDIR)/\", $(ALLAVPROGS))\n\nclean::\n\t$(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%)\n"
  },
  {
    "path": "src/fftools/cmdutils.c",
    "content": "/*\n * Various utilities for command line tools\n * Copyright (c) 2000-2003 Fabrice Bellard\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <string.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <math.h>\n#include <emscripten.h>\n\n/* Include only the enabled headers since some compilers (namely, Sun\n   Studio) will not omit unused inline functions and create undefined\n   references to libraries that are not being built. */\n\n#include \"config.h\"\n#include \"compat/va_copy.h\"\n#include \"libavformat/avformat.h\"\n#include \"libswscale/swscale.h\"\n#include \"libswscale/version.h\"\n#include \"libswresample/swresample.h\"\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/display.h\"\n#include \"libavutil/getenv_utf8.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/libm.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/eval.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/opt.h\"\n#include \"cmdutils.h\"\n#include \"fopen_utf8.h\"\n#include \"opt_common.h\"\n#ifdef _WIN32\n#include <windows.h>\n#include \"compat/w32dlfcn.h\"\n#endif\n\nAVDictionary *sws_dict;\nAVDictionary *swr_opts;\nAVDictionary *format_opts, *codec_opts;\n\nint hide_banner = 0;\n\nvoid uninit_opts(void)\n{\n    av_dict_free(&swr_opts);\n    av_dict_free(&sws_dict);\n    av_dict_free(&format_opts);\n    av_dict_free(&codec_opts);\n}\n\nvoid log_callback_help(void *ptr, int level, const char *fmt, va_list vl)\n{\n    vfprintf(stdout, fmt, vl);\n}\n\nvoid init_dynload(void)\n{\n#if HAVE_SETDLLDIRECTORY && defined(_WIN32)\n    /* Calling SetDllDirectory with the empty string (but not NULL) removes the\n     * current working directory from the DLL search path as a security pre-caution. */\n    SetDllDirectory(\"\");\n#endif\n}\n\nstatic void (*program_exit)(int ret);\n\nvoid register_exit(void (*cb)(int ret))\n{\n    program_exit = cb;\n}\n\nvoid exit_program(int ret)\n{\n    if (program_exit)\n        program_exit(ret);\n\n    /*\n     * abort() is used instead of exit() because exit() not only\n     * terminates ffmpeg but also the whole node.js program, which \n     * is not ideal.\n     *\n     * abort() terminiates the ffmpeg with an JS exception\n     *\n     *   RuntimeError: Aborted...\n     *\n     * This excpetion is catch and not visible to users.\n     *\n     */\n    EM_ASM({\n        Module.ret = $0;\n    }, ret);\n    abort();\n    // exit(ret);\n}\n\ndouble parse_number_or_die(const char *context, const char *numstr, int type,\n                           double min, double max)\n{\n    char *tail;\n    const char *error;\n    double d = av_strtod(numstr, &tail);\n    if (*tail)\n        error = \"Expected number for %s but found: %s\\n\";\n    else if (d < min || d > max)\n        error = \"The value for %s was %s which is not within %f - %f\\n\";\n    else if (type == OPT_INT64 && (int64_t)d != d)\n        error = \"Expected int64 for %s but found %s\\n\";\n    else if (type == OPT_INT && (int)d != d)\n        error = \"Expected int for %s but found %s\\n\";\n    else\n        return d;\n    av_log(NULL, AV_LOG_FATAL, error, context, numstr, min, max);\n    exit_program(1);\n    return 0;\n}\n\nint64_t parse_time_or_die(const char *context, const char *timestr,\n                          int is_duration)\n{\n    int64_t us;\n    if (av_parse_time(&us, timestr, is_duration) < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid %s specification for %s: %s\\n\",\n               is_duration ? \"duration\" : \"date\", context, timestr);\n        exit_program(1);\n    }\n    return us;\n}\n\nvoid show_help_options(const OptionDef *options, const char *msg, int req_flags,\n                       int rej_flags, int alt_flags)\n{\n    const OptionDef *po;\n    int first;\n\n    first = 1;\n    for (po = options; po->name; po++) {\n        char buf[128];\n\n        if (((po->flags & req_flags) != req_flags) ||\n            (alt_flags && !(po->flags & alt_flags)) ||\n            (po->flags & rej_flags))\n            continue;\n\n        if (first) {\n            printf(\"%s\\n\", msg);\n            first = 0;\n        }\n        av_strlcpy(buf, po->name, sizeof(buf));\n        if (po->argname) {\n            av_strlcat(buf, \" \", sizeof(buf));\n            av_strlcat(buf, po->argname, sizeof(buf));\n        }\n        printf(\"-%-17s  %s\\n\", buf, po->help);\n    }\n    printf(\"\\n\");\n}\n\nvoid show_help_children(const AVClass *class, int flags)\n{\n    void *iter = NULL;\n    const AVClass *child;\n    if (class->option) {\n        av_opt_show2(&class, NULL, flags, 0);\n        printf(\"\\n\");\n    }\n\n    while (child = av_opt_child_class_iterate(class, &iter))\n        show_help_children(child, flags);\n}\n\nstatic const OptionDef *find_option(const OptionDef *po, const char *name)\n{\n    while (po->name) {\n        const char *end;\n        if (av_strstart(name, po->name, &end) && (!*end || *end == ':'))\n            break;\n        po++;\n    }\n    return po;\n}\n\n/* _WIN32 means using the windows libc - cygwin doesn't define that\n * by default. HAVE_COMMANDLINETOARGVW is true on cygwin, while\n * it doesn't provide the actual command line via GetCommandLineW(). */\n#if HAVE_COMMANDLINETOARGVW && defined(_WIN32)\n#include <shellapi.h>\n/* Will be leaked on exit */\nstatic char** win32_argv_utf8 = NULL;\nstatic int win32_argc = 0;\n\n/**\n * Prepare command line arguments for executable.\n * For Windows - perform wide-char to UTF-8 conversion.\n * Input arguments should be main() function arguments.\n * @param argc_ptr Arguments number (including executable)\n * @param argv_ptr Arguments list.\n */\nstatic void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)\n{\n    char *argstr_flat;\n    wchar_t **argv_w;\n    int i, buffsize = 0, offset = 0;\n\n    if (win32_argv_utf8) {\n        *argc_ptr = win32_argc;\n        *argv_ptr = win32_argv_utf8;\n        return;\n    }\n\n    win32_argc = 0;\n    argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc);\n    if (win32_argc <= 0 || !argv_w)\n        return;\n\n    /* determine the UTF-8 buffer size (including NULL-termination symbols) */\n    for (i = 0; i < win32_argc; i++)\n        buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,\n                                        NULL, 0, NULL, NULL);\n\n    win32_argv_utf8 = av_mallocz(sizeof(char *) * (win32_argc + 1) + buffsize);\n    argstr_flat     = (char *)win32_argv_utf8 + sizeof(char *) * (win32_argc + 1);\n    if (!win32_argv_utf8) {\n        LocalFree(argv_w);\n        return;\n    }\n\n    for (i = 0; i < win32_argc; i++) {\n        win32_argv_utf8[i] = &argstr_flat[offset];\n        offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1,\n                                      &argstr_flat[offset],\n                                      buffsize - offset, NULL, NULL);\n    }\n    win32_argv_utf8[i] = NULL;\n    LocalFree(argv_w);\n\n    *argc_ptr = win32_argc;\n    *argv_ptr = win32_argv_utf8;\n}\n#else\nstatic inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr)\n{\n    /* nothing to do */\n}\n#endif /* HAVE_COMMANDLINETOARGVW */\n\nstatic int write_option(void *optctx, const OptionDef *po, const char *opt,\n                        const char *arg)\n{\n    /* new-style options contain an offset into optctx, old-style address of\n     * a global var*/\n    void *dst = po->flags & (OPT_OFFSET | OPT_SPEC) ?\n                (uint8_t *)optctx + po->u.off : po->u.dst_ptr;\n    int *dstcount;\n\n    if (po->flags & OPT_SPEC) {\n        SpecifierOpt **so = dst;\n        char *p = strchr(opt, ':');\n        char *str;\n\n        dstcount = (int *)(so + 1);\n        *so = grow_array(*so, sizeof(**so), dstcount, *dstcount + 1);\n        str = av_strdup(p ? p + 1 : \"\");\n        if (!str)\n            return AVERROR(ENOMEM);\n        (*so)[*dstcount - 1].specifier = str;\n        dst = &(*so)[*dstcount - 1].u;\n    }\n\n    if (po->flags & OPT_STRING) {\n        char *str;\n        str = av_strdup(arg);\n        av_freep(dst);\n        if (!str)\n            return AVERROR(ENOMEM);\n        *(char **)dst = str;\n    } else if (po->flags & OPT_BOOL || po->flags & OPT_INT) {\n        *(int *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);\n    } else if (po->flags & OPT_INT64) {\n        *(int64_t *)dst = parse_number_or_die(opt, arg, OPT_INT64, INT64_MIN, INT64_MAX);\n    } else if (po->flags & OPT_TIME) {\n        *(int64_t *)dst = parse_time_or_die(opt, arg, 1);\n    } else if (po->flags & OPT_FLOAT) {\n        *(float *)dst = parse_number_or_die(opt, arg, OPT_FLOAT, -INFINITY, INFINITY);\n    } else if (po->flags & OPT_DOUBLE) {\n        *(double *)dst = parse_number_or_die(opt, arg, OPT_DOUBLE, -INFINITY, INFINITY);\n    } else if (po->u.func_arg) {\n        int ret = po->u.func_arg(optctx, opt, arg);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Failed to set value '%s' for option '%s': %s\\n\",\n                   arg, opt, av_err2str(ret));\n            return ret;\n        }\n    }\n    if (po->flags & OPT_EXIT)\n        exit_program(0);\n\n    return 0;\n}\n\nint parse_option(void *optctx, const char *opt, const char *arg,\n                 const OptionDef *options)\n{\n    static const OptionDef opt_avoptions = {\n        .name       = \"AVOption passthrough\",\n        .flags      = HAS_ARG,\n        .u.func_arg = opt_default,\n    };\n\n    const OptionDef *po;\n    int ret;\n\n    po = find_option(options, opt);\n    if (!po->name && opt[0] == 'n' && opt[1] == 'o') {\n        /* handle 'no' bool option */\n        po = find_option(options, opt + 2);\n        if ((po->name && (po->flags & OPT_BOOL)))\n            arg = \"0\";\n    } else if (po->flags & OPT_BOOL)\n        arg = \"1\";\n\n    if (!po->name)\n        po = &opt_avoptions;\n    if (!po->name) {\n        av_log(NULL, AV_LOG_ERROR, \"Unrecognized option '%s'\\n\", opt);\n        return AVERROR(EINVAL);\n    }\n    if (po->flags & HAS_ARG && !arg) {\n        av_log(NULL, AV_LOG_ERROR, \"Missing argument for option '%s'\\n\", opt);\n        return AVERROR(EINVAL);\n    }\n\n    ret = write_option(optctx, po, opt, arg);\n    if (ret < 0)\n        return ret;\n\n    return !!(po->flags & HAS_ARG);\n}\n\nvoid parse_options(void *optctx, int argc, char **argv, const OptionDef *options,\n                   void (*parse_arg_function)(void *, const char*))\n{\n    const char *opt;\n    int optindex, handleoptions = 1, ret;\n\n    /* perform system-dependent conversions for arguments list */\n    prepare_app_arguments(&argc, &argv);\n\n    /* parse options */\n    optindex = 1;\n    while (optindex < argc) {\n        opt = argv[optindex++];\n\n        if (handleoptions && opt[0] == '-' && opt[1] != '\\0') {\n            if (opt[1] == '-' && opt[2] == '\\0') {\n                handleoptions = 0;\n                continue;\n            }\n            opt++;\n\n            if ((ret = parse_option(optctx, opt, argv[optindex], options)) < 0)\n                exit_program(1);\n            optindex += ret;\n        } else {\n            if (parse_arg_function)\n                parse_arg_function(optctx, opt);\n        }\n    }\n}\n\nint parse_optgroup(void *optctx, OptionGroup *g)\n{\n    int i, ret;\n\n    av_log(NULL, AV_LOG_DEBUG, \"Parsing a group of options: %s %s.\\n\",\n           g->group_def->name, g->arg);\n\n    for (i = 0; i < g->nb_opts; i++) {\n        Option *o = &g->opts[i];\n\n        if (g->group_def->flags &&\n            !(g->group_def->flags & o->opt->flags)) {\n            av_log(NULL, AV_LOG_ERROR, \"Option %s (%s) cannot be applied to \"\n                   \"%s %s -- you are trying to apply an input option to an \"\n                   \"output file or vice versa. Move this option before the \"\n                   \"file it belongs to.\\n\", o->key, o->opt->help,\n                   g->group_def->name, g->arg);\n            return AVERROR(EINVAL);\n        }\n\n        av_log(NULL, AV_LOG_DEBUG, \"Applying option %s (%s) with argument %s.\\n\",\n               o->key, o->opt->help, o->val);\n\n        ret = write_option(optctx, o->opt, o->key, o->val);\n        if (ret < 0)\n            return ret;\n    }\n\n    av_log(NULL, AV_LOG_DEBUG, \"Successfully parsed a group of options.\\n\");\n\n    return 0;\n}\n\nint locate_option(int argc, char **argv, const OptionDef *options,\n                  const char *optname)\n{\n    const OptionDef *po;\n    int i;\n\n    for (i = 1; i < argc; i++) {\n        const char *cur_opt = argv[i];\n\n        if (*cur_opt++ != '-')\n            continue;\n\n        po = find_option(options, cur_opt);\n        if (!po->name && cur_opt[0] == 'n' && cur_opt[1] == 'o')\n            po = find_option(options, cur_opt + 2);\n\n        if ((!po->name && !strcmp(cur_opt, optname)) ||\n             (po->name && !strcmp(optname, po->name)))\n            return i;\n\n        if (!po->name || po->flags & HAS_ARG)\n            i++;\n    }\n    return 0;\n}\n\nstatic void dump_argument(FILE *report_file, const char *a)\n{\n    const unsigned char *p;\n\n    for (p = a; *p; p++)\n        if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||\n              *p == '_' || (*p >= 'a' && *p <= 'z')))\n            break;\n    if (!*p) {\n        fputs(a, report_file);\n        return;\n    }\n    fputc('\"', report_file);\n    for (p = a; *p; p++) {\n        if (*p == '\\\\' || *p == '\"' || *p == '$' || *p == '`')\n            fprintf(report_file, \"\\\\%c\", *p);\n        else if (*p < ' ' || *p > '~')\n            fprintf(report_file, \"\\\\x%02x\", *p);\n        else\n            fputc(*p, report_file);\n    }\n    fputc('\"', report_file);\n}\n\nstatic void check_options(const OptionDef *po)\n{\n    while (po->name) {\n        if (po->flags & OPT_PERFILE)\n            av_assert0(po->flags & (OPT_INPUT | OPT_OUTPUT));\n        po++;\n    }\n}\n\nvoid parse_loglevel(int argc, char **argv, const OptionDef *options)\n{\n    int idx = locate_option(argc, argv, options, \"loglevel\");\n    char *env;\n\n    check_options(options);\n\n    if (!idx)\n        idx = locate_option(argc, argv, options, \"v\");\n    if (idx && argv[idx + 1])\n        opt_loglevel(NULL, \"loglevel\", argv[idx + 1]);\n    idx = locate_option(argc, argv, options, \"report\");\n    env = getenv_utf8(\"FFREPORT\");\n    if (env || idx) {\n        FILE *report_file = NULL;\n        init_report(env, &report_file);\n        if (report_file) {\n            int i;\n            fprintf(report_file, \"Command line:\\n\");\n            for (i = 0; i < argc; i++) {\n                dump_argument(report_file, argv[i]);\n                fputc(i < argc - 1 ? ' ' : '\\n', report_file);\n            }\n            fflush(report_file);\n        }\n    }\n    freeenv_utf8(env);\n    idx = locate_option(argc, argv, options, \"hide_banner\");\n    if (idx)\n        hide_banner = 1;\n}\n\nstatic const AVOption *opt_find(void *obj, const char *name, const char *unit,\n                            int opt_flags, int search_flags)\n{\n    const AVOption *o = av_opt_find(obj, name, unit, opt_flags, search_flags);\n    if(o && !o->flags)\n        return NULL;\n    return o;\n}\n\n#define FLAGS (o->type == AV_OPT_TYPE_FLAGS && (arg[0]=='-' || arg[0]=='+')) ? AV_DICT_APPEND : 0\nint opt_default(void *optctx, const char *opt, const char *arg)\n{\n    const AVOption *o;\n    int consumed = 0;\n    char opt_stripped[128];\n    const char *p;\n    const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class();\n#if CONFIG_SWSCALE\n    const AVClass *sc = sws_get_class();\n#endif\n#if CONFIG_SWRESAMPLE\n    const AVClass *swr_class = swr_get_class();\n#endif\n\n    if (!strcmp(opt, \"debug\") || !strcmp(opt, \"fdebug\"))\n        av_log_set_level(AV_LOG_DEBUG);\n\n    if (!(p = strchr(opt, ':')))\n        p = opt + strlen(opt);\n    av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1));\n\n    if ((o = opt_find(&cc, opt_stripped, NULL, 0,\n                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) ||\n        ((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') &&\n         (o = opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) {\n        av_dict_set(&codec_opts, opt, arg, FLAGS);\n        consumed = 1;\n    }\n    if ((o = opt_find(&fc, opt, NULL, 0,\n                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {\n        av_dict_set(&format_opts, opt, arg, FLAGS);\n        if (consumed)\n            av_log(NULL, AV_LOG_VERBOSE, \"Routing option %s to both codec and muxer layer\\n\", opt);\n        consumed = 1;\n    }\n#if CONFIG_SWSCALE\n    if (!consumed && (o = opt_find(&sc, opt, NULL, 0,\n                         AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {\n        if (!strcmp(opt, \"srcw\") || !strcmp(opt, \"srch\") ||\n            !strcmp(opt, \"dstw\") || !strcmp(opt, \"dsth\") ||\n            !strcmp(opt, \"src_format\") || !strcmp(opt, \"dst_format\")) {\n            av_log(NULL, AV_LOG_ERROR, \"Directly using swscale dimensions/format options is not supported, please use the -s or -pix_fmt options\\n\");\n            return AVERROR(EINVAL);\n        }\n        av_dict_set(&sws_dict, opt, arg, FLAGS);\n\n        consumed = 1;\n    }\n#else\n    if (!consumed && !strcmp(opt, \"sws_flags\")) {\n        av_log(NULL, AV_LOG_WARNING, \"Ignoring %s %s, due to disabled swscale\\n\", opt, arg);\n        consumed = 1;\n    }\n#endif\n#if CONFIG_SWRESAMPLE\n    if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,\n                                    AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {\n        av_dict_set(&swr_opts, opt, arg, FLAGS);\n        consumed = 1;\n    }\n#endif\n\n    if (consumed)\n        return 0;\n    return AVERROR_OPTION_NOT_FOUND;\n}\n\n/*\n * Check whether given option is a group separator.\n *\n * @return index of the group definition that matched or -1 if none\n */\nstatic int match_group_separator(const OptionGroupDef *groups, int nb_groups,\n                                 const char *opt)\n{\n    int i;\n\n    for (i = 0; i < nb_groups; i++) {\n        const OptionGroupDef *p = &groups[i];\n        if (p->sep && !strcmp(p->sep, opt))\n            return i;\n    }\n\n    return -1;\n}\n\n/*\n * Finish parsing an option group.\n *\n * @param group_idx which group definition should this group belong to\n * @param arg argument of the group delimiting option\n */\nstatic void finish_group(OptionParseContext *octx, int group_idx,\n                         const char *arg)\n{\n    OptionGroupList *l = &octx->groups[group_idx];\n    OptionGroup *g;\n\n    GROW_ARRAY(l->groups, l->nb_groups);\n    g = &l->groups[l->nb_groups - 1];\n\n    *g             = octx->cur_group;\n    g->arg         = arg;\n    g->group_def   = l->group_def;\n    g->sws_dict    = sws_dict;\n    g->swr_opts    = swr_opts;\n    g->codec_opts  = codec_opts;\n    g->format_opts = format_opts;\n\n    codec_opts  = NULL;\n    format_opts = NULL;\n    sws_dict    = NULL;\n    swr_opts    = NULL;\n\n    memset(&octx->cur_group, 0, sizeof(octx->cur_group));\n}\n\n/*\n * Add an option instance to currently parsed group.\n */\nstatic void add_opt(OptionParseContext *octx, const OptionDef *opt,\n                    const char *key, const char *val)\n{\n    int global = !(opt->flags & (OPT_PERFILE | OPT_SPEC | OPT_OFFSET));\n    OptionGroup *g = global ? &octx->global_opts : &octx->cur_group;\n\n    GROW_ARRAY(g->opts, g->nb_opts);\n    g->opts[g->nb_opts - 1].opt = opt;\n    g->opts[g->nb_opts - 1].key = key;\n    g->opts[g->nb_opts - 1].val = val;\n}\n\nstatic void init_parse_context(OptionParseContext *octx,\n                               const OptionGroupDef *groups, int nb_groups)\n{\n    static const OptionGroupDef global_group = { \"global\" };\n    int i;\n\n    memset(octx, 0, sizeof(*octx));\n\n    octx->nb_groups = nb_groups;\n    octx->groups    = av_calloc(octx->nb_groups, sizeof(*octx->groups));\n    if (!octx->groups)\n        exit_program(1);\n\n    for (i = 0; i < octx->nb_groups; i++)\n        octx->groups[i].group_def = &groups[i];\n\n    octx->global_opts.group_def = &global_group;\n    octx->global_opts.arg       = \"\";\n}\n\nvoid uninit_parse_context(OptionParseContext *octx)\n{\n    int i, j;\n\n    for (i = 0; i < octx->nb_groups; i++) {\n        OptionGroupList *l = &octx->groups[i];\n\n        for (j = 0; j < l->nb_groups; j++) {\n            av_freep(&l->groups[j].opts);\n            av_dict_free(&l->groups[j].codec_opts);\n            av_dict_free(&l->groups[j].format_opts);\n\n            av_dict_free(&l->groups[j].sws_dict);\n            av_dict_free(&l->groups[j].swr_opts);\n        }\n        av_freep(&l->groups);\n    }\n    av_freep(&octx->groups);\n\n    av_freep(&octx->cur_group.opts);\n    av_freep(&octx->global_opts.opts);\n\n    uninit_opts();\n}\n\nint split_commandline(OptionParseContext *octx, int argc, char *argv[],\n                      const OptionDef *options,\n                      const OptionGroupDef *groups, int nb_groups)\n{\n    int optindex = 1;\n    int dashdash = -2;\n\n    /* perform system-dependent conversions for arguments list */\n    prepare_app_arguments(&argc, &argv);\n\n    init_parse_context(octx, groups, nb_groups);\n    av_log(NULL, AV_LOG_DEBUG, \"Splitting the commandline.\\n\");\n\n    while (optindex < argc) {\n        const char *opt = argv[optindex++], *arg;\n        const OptionDef *po;\n        int ret;\n\n        av_log(NULL, AV_LOG_DEBUG, \"Reading option '%s' ...\", opt);\n\n        if (opt[0] == '-' && opt[1] == '-' && !opt[2]) {\n            dashdash = optindex;\n            continue;\n        }\n        /* unnamed group separators, e.g. output filename */\n        if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) {\n            finish_group(octx, 0, opt);\n            av_log(NULL, AV_LOG_DEBUG, \" matched as %s.\\n\", groups[0].name);\n            continue;\n        }\n        opt++;\n\n#define GET_ARG(arg)                                                           \\\ndo {                                                                           \\\n    arg = argv[optindex++];                                                    \\\n    if (!arg) {                                                                \\\n        av_log(NULL, AV_LOG_ERROR, \"Missing argument for option '%s'.\\n\", opt);\\\n        return AVERROR(EINVAL);                                                \\\n    }                                                                          \\\n} while (0)\n\n        /* named group separators, e.g. -i */\n        if ((ret = match_group_separator(groups, nb_groups, opt)) >= 0) {\n            GET_ARG(arg);\n            finish_group(octx, ret, arg);\n            av_log(NULL, AV_LOG_DEBUG, \" matched as %s with argument '%s'.\\n\",\n                   groups[ret].name, arg);\n            continue;\n        }\n\n        /* normal options */\n        po = find_option(options, opt);\n        if (po->name) {\n            if (po->flags & OPT_EXIT) {\n                /* optional argument, e.g. -h */\n                arg = argv[optindex++];\n            } else if (po->flags & HAS_ARG) {\n                GET_ARG(arg);\n            } else {\n                arg = \"1\";\n            }\n\n            add_opt(octx, po, opt, arg);\n            av_log(NULL, AV_LOG_DEBUG, \" matched as option '%s' (%s) with \"\n                   \"argument '%s'.\\n\", po->name, po->help, arg);\n            continue;\n        }\n\n        /* AVOptions */\n        if (argv[optindex]) {\n            ret = opt_default(NULL, opt, argv[optindex]);\n            if (ret >= 0) {\n                av_log(NULL, AV_LOG_DEBUG, \" matched as AVOption '%s' with \"\n                       \"argument '%s'.\\n\", opt, argv[optindex]);\n                optindex++;\n                continue;\n            } else if (ret != AVERROR_OPTION_NOT_FOUND) {\n                av_log(NULL, AV_LOG_ERROR, \"Error parsing option '%s' \"\n                       \"with argument '%s'.\\n\", opt, argv[optindex]);\n                return ret;\n            }\n        }\n\n        /* boolean -nofoo options */\n        if (opt[0] == 'n' && opt[1] == 'o' &&\n            (po = find_option(options, opt + 2)) &&\n            po->name && po->flags & OPT_BOOL) {\n            add_opt(octx, po, opt, \"0\");\n            av_log(NULL, AV_LOG_DEBUG, \" matched as option '%s' (%s) with \"\n                   \"argument 0.\\n\", po->name, po->help);\n            continue;\n        }\n\n        av_log(NULL, AV_LOG_ERROR, \"Unrecognized option '%s'.\\n\", opt);\n        return AVERROR_OPTION_NOT_FOUND;\n    }\n\n    if (octx->cur_group.nb_opts || codec_opts || format_opts)\n        av_log(NULL, AV_LOG_WARNING, \"Trailing option(s) found in the \"\n               \"command: may be ignored.\\n\");\n\n    av_log(NULL, AV_LOG_DEBUG, \"Finished splitting the commandline.\\n\");\n\n    return 0;\n}\n\nvoid print_error(const char *filename, int err)\n{\n    char errbuf[128];\n    const char *errbuf_ptr = errbuf;\n\n    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)\n        errbuf_ptr = strerror(AVUNERROR(err));\n    av_log(NULL, AV_LOG_ERROR, \"%s: %s\\n\", filename, errbuf_ptr);\n}\n\nint read_yesno(void)\n{\n    int c = getchar();\n    int yesno = (av_toupper(c) == 'Y');\n\n    while (c != '\\n' && c != EOF)\n        c = getchar();\n\n    return yesno;\n}\n\nFILE *get_preset_file(char *filename, size_t filename_size,\n                      const char *preset_name, int is_path,\n                      const char *codec_name)\n{\n    FILE *f = NULL;\n    int i;\n#if HAVE_GETMODULEHANDLE && defined(_WIN32)\n    char *datadir = NULL;\n#endif\n    char *env_home = getenv_utf8(\"HOME\");\n    char *env_ffmpeg_datadir = getenv_utf8(\"FFMPEG_DATADIR\");\n    const char *base[3] = { env_ffmpeg_datadir,\n                            env_home,   /* index=1(HOME) is special: search in a .ffmpeg subfolder */\n                            FFMPEG_DATADIR, };\n\n    if (is_path) {\n        av_strlcpy(filename, preset_name, filename_size);\n        f = fopen_utf8(filename, \"r\");\n    } else {\n#if HAVE_GETMODULEHANDLE && defined(_WIN32)\n        wchar_t *datadir_w = get_module_filename(NULL);\n        base[2] = NULL;\n\n        if (wchartoutf8(datadir_w, &datadir))\n            datadir = NULL;\n        av_free(datadir_w);\n\n        if (datadir)\n        {\n            char *ls;\n            for (ls = datadir; *ls; ls++)\n                if (*ls == '\\\\') *ls = '/';\n\n            if (ls = strrchr(datadir, '/'))\n            {\n                ptrdiff_t datadir_len = ls - datadir;\n                size_t desired_size = datadir_len + strlen(\"/ffpresets\") + 1;\n                char *new_datadir = av_realloc_array(\n                    datadir, desired_size, sizeof *datadir);\n                if (new_datadir) {\n                    datadir = new_datadir;\n                    datadir[datadir_len] = 0;\n                    strncat(datadir, \"/ffpresets\",  desired_size - 1 - datadir_len);\n                    base[2] = datadir;\n                }\n            }\n        }\n#endif\n        for (i = 0; i < 3 && !f; i++) {\n            if (!base[i])\n                continue;\n            snprintf(filename, filename_size, \"%s%s/%s.ffpreset\", base[i],\n                     i != 1 ? \"\" : \"/.ffmpeg\", preset_name);\n            f = fopen_utf8(filename, \"r\");\n            if (!f && codec_name) {\n                snprintf(filename, filename_size,\n                         \"%s%s/%s-%s.ffpreset\",\n                         base[i], i != 1 ? \"\" : \"/.ffmpeg\", codec_name,\n                         preset_name);\n                f = fopen_utf8(filename, \"r\");\n            }\n        }\n    }\n\n#if HAVE_GETMODULEHANDLE && defined(_WIN32)\n    av_free(datadir);\n#endif\n    freeenv_utf8(env_ffmpeg_datadir);\n    freeenv_utf8(env_home);\n    return f;\n}\n\nint check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)\n{\n    int ret = avformat_match_stream_specifier(s, st, spec);\n    if (ret < 0)\n        av_log(s, AV_LOG_ERROR, \"Invalid stream specifier: %s.\\n\", spec);\n    return ret;\n}\n\nAVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,\n                                AVFormatContext *s, AVStream *st, const AVCodec *codec)\n{\n    AVDictionary    *ret = NULL;\n    const AVDictionaryEntry *t = NULL;\n    int            flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM\n                                      : AV_OPT_FLAG_DECODING_PARAM;\n    char          prefix = 0;\n    const AVClass    *cc = avcodec_get_class();\n\n    if (!codec)\n        codec            = s->oformat ? avcodec_find_encoder(codec_id)\n                                      : avcodec_find_decoder(codec_id);\n\n    switch (st->codecpar->codec_type) {\n    case AVMEDIA_TYPE_VIDEO:\n        prefix  = 'v';\n        flags  |= AV_OPT_FLAG_VIDEO_PARAM;\n        break;\n    case AVMEDIA_TYPE_AUDIO:\n        prefix  = 'a';\n        flags  |= AV_OPT_FLAG_AUDIO_PARAM;\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        prefix  = 's';\n        flags  |= AV_OPT_FLAG_SUBTITLE_PARAM;\n        break;\n    }\n\n    while (t = av_dict_get(opts, \"\", t, AV_DICT_IGNORE_SUFFIX)) {\n        const AVClass *priv_class;\n        char *p = strchr(t->key, ':');\n\n        /* check stream specification in opt name */\n        if (p)\n            switch (check_stream_specifier(s, st, p + 1)) {\n            case  1: *p = 0; break;\n            case  0:         continue;\n            default:         exit_program(1);\n            }\n\n        if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||\n            !codec ||\n            ((priv_class = codec->priv_class) &&\n             av_opt_find(&priv_class, t->key, NULL, flags,\n                         AV_OPT_SEARCH_FAKE_OBJ)))\n            av_dict_set(&ret, t->key, t->value, 0);\n        else if (t->key[0] == prefix &&\n                 av_opt_find(&cc, t->key + 1, NULL, flags,\n                             AV_OPT_SEARCH_FAKE_OBJ))\n            av_dict_set(&ret, t->key + 1, t->value, 0);\n\n        if (p)\n            *p = ':';\n    }\n    return ret;\n}\n\nAVDictionary **setup_find_stream_info_opts(AVFormatContext *s,\n                                           AVDictionary *codec_opts)\n{\n    int i;\n    AVDictionary **opts;\n\n    if (!s->nb_streams)\n        return NULL;\n    opts = av_calloc(s->nb_streams, sizeof(*opts));\n    if (!opts) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"Could not alloc memory for stream options.\\n\");\n        exit_program(1);\n    }\n    for (i = 0; i < s->nb_streams; i++)\n        opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,\n                                    s, s->streams[i], NULL);\n    return opts;\n}\n\nvoid *grow_array(void *array, int elem_size, int *size, int new_size)\n{\n    if (new_size >= INT_MAX / elem_size) {\n        av_log(NULL, AV_LOG_ERROR, \"Array too big.\\n\");\n        exit_program(1);\n    }\n    if (*size < new_size) {\n        uint8_t *tmp = av_realloc_array(array, new_size, elem_size);\n        if (!tmp) {\n            av_log(NULL, AV_LOG_ERROR, \"Could not alloc buffer.\\n\");\n            exit_program(1);\n        }\n        memset(tmp + *size*elem_size, 0, (new_size-*size) * elem_size);\n        *size = new_size;\n        return tmp;\n    }\n    return array;\n}\n\nvoid *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems)\n{\n    void *new_elem;\n\n    if (!(new_elem = av_mallocz(elem_size)) ||\n        av_dynarray_add_nofree(ptr, nb_elems, new_elem) < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Could not alloc buffer.\\n\");\n        exit_program(1);\n    }\n    return new_elem;\n}\n\ndouble get_rotation(int32_t *displaymatrix)\n{\n    double theta = 0;\n    if (displaymatrix)\n        theta = -round(av_display_rotation_get((int32_t*) displaymatrix));\n\n    theta -= 360*floor(theta/360 + 0.9/360);\n\n    if (fabs(theta - 90*round(theta/90)) > 2)\n        av_log(NULL, AV_LOG_WARNING, \"Odd rotation angle.\\n\"\n               \"If you want to help, upload a sample \"\n               \"of this file to https://streams.videolan.org/upload/ \"\n               \"and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\");\n\n    return theta;\n}\n"
  },
  {
    "path": "src/fftools/cmdutils.h",
    "content": "/*\n * Various utilities for command line tools\n * copyright (c) 2003 Fabrice Bellard\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFTOOLS_CMDUTILS_H\n#define FFTOOLS_CMDUTILS_H\n\n#include <stdint.h>\n\n#include \"config.h\"\n#include \"libavcodec/avcodec.h\"\n#include \"libavfilter/avfilter.h\"\n#include \"libavformat/avformat.h\"\n#include \"libswscale/swscale.h\"\n\n#ifdef _WIN32\n#undef main /* We don't want SDL to override our main() */\n#endif\n\n/**\n * program name, defined by the program for show_version().\n */\nextern const char program_name[];\n\n/**\n * program birth year, defined by the program for show_banner()\n */\nextern const int program_birth_year;\n\nextern AVDictionary *sws_dict;\nextern AVDictionary *swr_opts;\nextern AVDictionary *format_opts, *codec_opts;\nextern int hide_banner;\n\n/**\n * Register a program-specific cleanup routine.\n */\nvoid register_exit(void (*cb)(int ret));\n\n/**\n * Wraps exit with a program-specific cleanup routine.\n */\nvoid exit_program(int ret) av_noreturn;\n\n/**\n * Initialize dynamic library loading\n */\nvoid init_dynload(void);\n\n/**\n * Uninitialize the cmdutils option system, in particular\n * free the *_opts contexts and their contents.\n */\nvoid uninit_opts(void);\n\n/**\n * Trivial log callback.\n * Only suitable for opt_help and similar since it lacks prefix handling.\n */\nvoid log_callback_help(void* ptr, int level, const char* fmt, va_list vl);\n\n/**\n * Fallback for options that are not explicitly handled, these will be\n * parsed through AVOptions.\n */\nint opt_default(void *optctx, const char *opt, const char *arg);\n\n/**\n * Limit the execution time.\n */\nint opt_timelimit(void *optctx, const char *opt, const char *arg);\n\n/**\n * Parse a string and return its corresponding value as a double.\n * Exit from the application if the string cannot be correctly\n * parsed or the corresponding value is invalid.\n *\n * @param context the context of the value to be set (e.g. the\n * corresponding command line option name)\n * @param numstr the string to be parsed\n * @param type the type (OPT_INT64 or OPT_FLOAT) as which the\n * string should be parsed\n * @param min the minimum valid accepted value\n * @param max the maximum valid accepted value\n */\ndouble parse_number_or_die(const char *context, const char *numstr, int type,\n                           double min, double max);\n\n/**\n * Parse a string specifying a time and return its corresponding\n * value as a number of microseconds. Exit from the application if\n * the string cannot be correctly parsed.\n *\n * @param context the context of the value to be set (e.g. the\n * corresponding command line option name)\n * @param timestr the string to be parsed\n * @param is_duration a flag which tells how to interpret timestr, if\n * not zero timestr is interpreted as a duration, otherwise as a\n * date\n *\n * @see av_parse_time()\n */\nint64_t parse_time_or_die(const char *context, const char *timestr,\n                          int is_duration);\n\ntypedef struct SpecifierOpt {\n    char *specifier;    /**< stream/chapter/program/... specifier */\n    union {\n        uint8_t *str;\n        int        i;\n        int64_t  i64;\n        uint64_t ui64;\n        float      f;\n        double   dbl;\n    } u;\n} SpecifierOpt;\n\ntypedef struct OptionDef {\n    const char *name;\n    int flags;\n#define HAS_ARG    0x0001\n#define OPT_BOOL   0x0002\n#define OPT_EXPERT 0x0004\n#define OPT_STRING 0x0008\n#define OPT_VIDEO  0x0010\n#define OPT_AUDIO  0x0020\n#define OPT_INT    0x0080\n#define OPT_FLOAT  0x0100\n#define OPT_SUBTITLE 0x0200\n#define OPT_INT64  0x0400\n#define OPT_EXIT   0x0800\n#define OPT_DATA   0x1000\n#define OPT_PERFILE  0x2000     /* the option is per-file (currently ffmpeg-only).\n                                   implied by OPT_OFFSET or OPT_SPEC */\n#define OPT_OFFSET 0x4000       /* option is specified as an offset in a passed optctx */\n#define OPT_SPEC   0x8000       /* option is to be stored in an array of SpecifierOpt.\n                                   Implies OPT_OFFSET. Next element after the offset is\n                                   an int containing element count in the array. */\n#define OPT_TIME  0x10000\n#define OPT_DOUBLE 0x20000\n#define OPT_INPUT  0x40000\n#define OPT_OUTPUT 0x80000\n     union {\n        void *dst_ptr;\n        int (*func_arg)(void *, const char *, const char *);\n        size_t off;\n    } u;\n    const char *help;\n    const char *argname;\n} OptionDef;\n\n/**\n * Print help for all options matching specified flags.\n *\n * @param options a list of options\n * @param msg title of this group. Only printed if at least one option matches.\n * @param req_flags print only options which have all those flags set.\n * @param rej_flags don't print options which have any of those flags set.\n * @param alt_flags print only options that have at least one of those flags set\n */\nvoid show_help_options(const OptionDef *options, const char *msg, int req_flags,\n                       int rej_flags, int alt_flags);\n\n/**\n * Show help for all options with given flags in class and all its\n * children.\n */\nvoid show_help_children(const AVClass *class, int flags);\n\n/**\n * Per-fftool specific help handler. Implemented in each\n * fftool, called by show_help().\n */\nvoid show_help_default(const char *opt, const char *arg);\n\n/**\n * Parse the command line arguments.\n *\n * @param optctx an opaque options context\n * @param argc   number of command line arguments\n * @param argv   values of command line arguments\n * @param options Array with the definitions required to interpret every\n * option of the form: -option_name [argument]\n * @param parse_arg_function Name of the function called to process every\n * argument without a leading option name flag. NULL if such arguments do\n * not have to be processed.\n */\nvoid parse_options(void *optctx, int argc, char **argv, const OptionDef *options,\n                   void (* parse_arg_function)(void *optctx, const char*));\n\n/**\n * Parse one given option.\n *\n * @return on success 1 if arg was consumed, 0 otherwise; negative number on error\n */\nint parse_option(void *optctx, const char *opt, const char *arg,\n                 const OptionDef *options);\n\n/**\n * An option extracted from the commandline.\n * Cannot use AVDictionary because of options like -map which can be\n * used multiple times.\n */\ntypedef struct Option {\n    const OptionDef  *opt;\n    const char       *key;\n    const char       *val;\n} Option;\n\ntypedef struct OptionGroupDef {\n    /**< group name */\n    const char *name;\n    /**\n     * Option to be used as group separator. Can be NULL for groups which\n     * are terminated by a non-option argument (e.g. ffmpeg output files)\n     */\n    const char *sep;\n    /**\n     * Option flags that must be set on each option that is\n     * applied to this group\n     */\n    int flags;\n} OptionGroupDef;\n\ntypedef struct OptionGroup {\n    const OptionGroupDef *group_def;\n    const char *arg;\n\n    Option *opts;\n    int  nb_opts;\n\n    AVDictionary *codec_opts;\n    AVDictionary *format_opts;\n    AVDictionary *sws_dict;\n    AVDictionary *swr_opts;\n} OptionGroup;\n\n/**\n * A list of option groups that all have the same group type\n * (e.g. input files or output files)\n */\ntypedef struct OptionGroupList {\n    const OptionGroupDef *group_def;\n\n    OptionGroup *groups;\n    int       nb_groups;\n} OptionGroupList;\n\ntypedef struct OptionParseContext {\n    OptionGroup global_opts;\n\n    OptionGroupList *groups;\n    int           nb_groups;\n\n    /* parsing state */\n    OptionGroup cur_group;\n} OptionParseContext;\n\n/**\n * Parse an options group and write results into optctx.\n *\n * @param optctx an app-specific options context. NULL for global options group\n */\nint parse_optgroup(void *optctx, OptionGroup *g);\n\n/**\n * Split the commandline into an intermediate form convenient for further\n * processing.\n *\n * The commandline is assumed to be composed of options which either belong to a\n * group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global\n * (everything else).\n *\n * A group (defined by an OptionGroupDef struct) is a sequence of options\n * terminated by either a group separator option (e.g. -i) or a parameter that\n * is not an option (doesn't start with -). A group without a separator option\n * must always be first in the supplied groups list.\n *\n * All options within the same group are stored in one OptionGroup struct in an\n * OptionGroupList, all groups with the same group definition are stored in one\n * OptionGroupList in OptionParseContext.groups. The order of group lists is the\n * same as the order of group definitions.\n */\nint split_commandline(OptionParseContext *octx, int argc, char *argv[],\n                      const OptionDef *options,\n                      const OptionGroupDef *groups, int nb_groups);\n\n/**\n * Free all allocated memory in an OptionParseContext.\n */\nvoid uninit_parse_context(OptionParseContext *octx);\n\n/**\n * Find the '-loglevel' option in the command line args and apply it.\n */\nvoid parse_loglevel(int argc, char **argv, const OptionDef *options);\n\n/**\n * Return index of option opt in argv or 0 if not found.\n */\nint locate_option(int argc, char **argv, const OptionDef *options,\n                  const char *optname);\n\n/**\n * Check if the given stream matches a stream specifier.\n *\n * @param s  Corresponding format context.\n * @param st Stream from s to be checked.\n * @param spec A stream specifier of the [v|a|s|d]:[\\<stream index\\>] form.\n *\n * @return 1 if the stream matches, 0 if it doesn't, <0 on error\n */\nint check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);\n\n/**\n * Filter out options for given codec.\n *\n * Create a new options dictionary containing only the options from\n * opts which apply to the codec with ID codec_id.\n *\n * @param opts     dictionary to place options in\n * @param codec_id ID of the codec that should be filtered for\n * @param s Corresponding format context.\n * @param st A stream from s for which the options should be filtered.\n * @param codec The particular codec for which the options should be filtered.\n *              If null, the default one is looked up according to the codec id.\n * @return a pointer to the created dictionary\n */\nAVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,\n                                AVFormatContext *s, AVStream *st, const AVCodec *codec);\n\n/**\n * Setup AVCodecContext options for avformat_find_stream_info().\n *\n * Create an array of dictionaries, one dictionary for each stream\n * contained in s.\n * Each dictionary will contain the options from codec_opts which can\n * be applied to the corresponding stream codec context.\n *\n * @return pointer to the created array of dictionaries.\n * Calls exit() on failure.\n */\nAVDictionary **setup_find_stream_info_opts(AVFormatContext *s,\n                                           AVDictionary *codec_opts);\n\n/**\n * Print an error message to stderr, indicating filename and a human\n * readable description of the error code err.\n *\n * If strerror_r() is not available the use of this function in a\n * multithreaded application may be unsafe.\n *\n * @see av_strerror()\n */\nvoid print_error(const char *filename, int err);\n\n/**\n * Print the program banner to stderr. The banner contents depend on the\n * current version of the repository and of the libav* libraries used by\n * the program.\n */\nvoid show_banner(int argc, char **argv, const OptionDef *options);\n\n/**\n * Return a positive value if a line read from standard input\n * starts with [yY], otherwise return 0.\n */\nint read_yesno(void);\n\n/**\n * Get a file corresponding to a preset file.\n *\n * If is_path is non-zero, look for the file in the path preset_name.\n * Otherwise search for a file named arg.ffpreset in the directories\n * $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined\n * at configuration time or in a \"ffpresets\" folder along the executable\n * on win32, in that order. If no such file is found and\n * codec_name is defined, then search for a file named\n * codec_name-preset_name.avpreset in the above-mentioned directories.\n *\n * @param filename buffer where the name of the found filename is written\n * @param filename_size size in bytes of the filename buffer\n * @param preset_name name of the preset to search\n * @param is_path tell if preset_name is a filename path\n * @param codec_name name of the codec for which to look for the\n * preset, may be NULL\n */\nFILE *get_preset_file(char *filename, size_t filename_size,\n                      const char *preset_name, int is_path, const char *codec_name);\n\n/**\n * Realloc array to hold new_size elements of elem_size.\n * Calls exit() on failure.\n *\n * @param array array to reallocate\n * @param elem_size size in bytes of each element\n * @param size new element count will be written here\n * @param new_size number of elements to place in reallocated array\n * @return reallocated array\n */\nvoid *grow_array(void *array, int elem_size, int *size, int new_size);\n\n/**\n * Atomically add a new element to an array of pointers, i.e. allocate\n * a new entry, reallocate the array of pointers and make the new last\n * member of this array point to the newly allocated buffer.\n * Calls exit() on failure.\n *\n * @param array     array of pointers to reallocate\n * @param elem_size size of the new element to allocate\n * @param nb_elems  pointer to the number of elements of the array array;\n *                  *nb_elems will be incremented by one by this function.\n * @return pointer to the newly allocated entry\n */\nvoid *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);\n\n#define GROW_ARRAY(array, nb_elems)\\\n    array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)\n\n#define ALLOC_ARRAY_ELEM(array, nb_elems)\\\n    allocate_array_elem(&array, sizeof(*array[0]), &nb_elems)\n\n#define GET_PIX_FMT_NAME(pix_fmt)\\\n    const char *name = av_get_pix_fmt_name(pix_fmt);\n\n#define GET_CODEC_NAME(id)\\\n    const char *name = avcodec_descriptor_get(id)->name;\n\n#define GET_SAMPLE_FMT_NAME(sample_fmt)\\\n    const char *name = av_get_sample_fmt_name(sample_fmt)\n\n#define GET_SAMPLE_RATE_NAME(rate)\\\n    char name[16];\\\n    snprintf(name, sizeof(name), \"%d\", rate);\n\ndouble get_rotation(int32_t *displaymatrix);\n\n#endif /* FFTOOLS_CMDUTILS_H */\n"
  },
  {
    "path": "src/fftools/ffmpeg.c",
    "content": "/*\n * Copyright (c) 2000-2003 Fabrice Bellard\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * multimedia converter based on the FFmpeg libraries\n */\n\n#include \"config.h\"\n#include <ctype.h>\n#include <string.h>\n#include <math.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <limits.h>\n#include <stdatomic.h>\n#include <stdint.h>\n#include <emscripten.h>\n\n#if HAVE_IO_H\n#include <io.h>\n#endif\n#if HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"libavformat/avformat.h\"\n#include \"libavdevice/avdevice.h\"\n#include \"libswresample/swresample.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/samplefmt.h\"\n#include \"libavutil/fifo.h\"\n#include \"libavutil/hwcontext.h\"\n#include \"libavutil/internal.h\"\n#include \"libavutil/intreadwrite.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/display.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/libm.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/timestamp.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavutil/time.h\"\n#include \"libavutil/thread.h\"\n#include \"libavutil/threadmessage.h\"\n#include \"libavcodec/mathops.h\"\n#include \"libavcodec/version.h\"\n#include \"libavformat/os_support.h\"\n\n# include \"libavfilter/avfilter.h\"\n# include \"libavfilter/buffersrc.h\"\n# include \"libavfilter/buffersink.h\"\n\n#if HAVE_SYS_RESOURCE_H\n#include <sys/time.h>\n#include <sys/types.h>\n#include <sys/resource.h>\n#elif HAVE_GETPROCESSTIMES\n#include <windows.h>\n#endif\n#if HAVE_GETPROCESSMEMORYINFO\n#include <windows.h>\n#include <psapi.h>\n#endif\n#if HAVE_SETCONSOLECTRLHANDLER\n#include <windows.h>\n#endif\n\n\n#if HAVE_SYS_SELECT_H\n#include <sys/select.h>\n#endif\n\n#if HAVE_TERMIOS_H\n#include <fcntl.h>\n#include <sys/ioctl.h>\n#include <sys/time.h>\n#include <termios.h>\n#elif HAVE_KBHIT\n#include <conio.h>\n#endif\n\n#include <time.h>\n\n#include \"ffmpeg.h\"\n#include \"cmdutils.h\"\n\n#include \"libavutil/avassert.h\"\n\nconst char program_name[] = \"ffmpeg\";\nconst int program_birth_year = 2000;\n\nstatic FILE *vstats_file;\n\nconst char *const forced_keyframes_const_names[] = {\n    \"n\",\n    \"n_forced\",\n    \"prev_forced_n\",\n    \"prev_forced_t\",\n    \"t\",\n    NULL\n};\n\ntypedef struct BenchmarkTimeStamps {\n    int64_t real_usec;\n    int64_t user_usec;\n    int64_t sys_usec;\n} BenchmarkTimeStamps;\n\nstatic BenchmarkTimeStamps get_benchmark_time_stamps(void);\nstatic int64_t getmaxrss(void);\nstatic int ifilter_has_all_input_formats(FilterGraph *fg);\n\nstatic int64_t nb_frames_dup = 0;\nstatic uint64_t dup_warning = 1000;\nstatic int64_t nb_frames_drop = 0;\nstatic int64_t decode_error_stat[2];\nunsigned nb_output_dumped = 0;\n\nint want_sdp = 1;\n\nstatic BenchmarkTimeStamps current_time;\nAVIOContext *progress_avio = NULL;\n\nstatic uint8_t *subtitle_out;\n\nInputStream **input_streams = NULL;\nint        nb_input_streams = 0;\nInputFile   **input_files   = NULL;\nint        nb_input_files   = 0;\n\nOutputStream **output_streams = NULL;\nint         nb_output_streams = 0;\nOutputFile   **output_files   = NULL;\nint         nb_output_files   = 0;\n\nFilterGraph **filtergraphs;\nint        nb_filtergraphs;\n\n#if HAVE_TERMIOS_H\n\n/* init terminal so that we can grab keys */\nstatic struct termios oldtty;\nstatic int restore_tty;\n#endif\n\n#if HAVE_THREADS\nstatic void free_input_threads(void);\n#endif\n\n/* sub2video hack:\n   Convert subtitles to video with alpha to insert them in filter graphs.\n   This is a temporary solution until libavfilter gets real subtitles support.\n */\n\nstatic int sub2video_get_blank_frame(InputStream *ist)\n{\n    int ret;\n    AVFrame *frame = ist->sub2video.frame;\n\n    av_frame_unref(frame);\n    ist->sub2video.frame->width  = ist->dec_ctx->width  ? ist->dec_ctx->width  : ist->sub2video.w;\n    ist->sub2video.frame->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;\n    ist->sub2video.frame->format = AV_PIX_FMT_RGB32;\n    if ((ret = av_frame_get_buffer(frame, 0)) < 0)\n        return ret;\n    memset(frame->data[0], 0, frame->height * frame->linesize[0]);\n    return 0;\n}\n\nstatic void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h,\n                                AVSubtitleRect *r)\n{\n    uint32_t *pal, *dst2;\n    uint8_t *src, *src2;\n    int x, y;\n\n    if (r->type != SUBTITLE_BITMAP) {\n        av_log(NULL, AV_LOG_WARNING, \"sub2video: non-bitmap subtitle\\n\");\n        return;\n    }\n    if (r->x < 0 || r->x + r->w > w || r->y < 0 || r->y + r->h > h) {\n        av_log(NULL, AV_LOG_WARNING, \"sub2video: rectangle (%d %d %d %d) overflowing %d %d\\n\",\n            r->x, r->y, r->w, r->h, w, h\n        );\n        return;\n    }\n\n    dst += r->y * dst_linesize + r->x * 4;\n    src = r->data[0];\n    pal = (uint32_t *)r->data[1];\n    for (y = 0; y < r->h; y++) {\n        dst2 = (uint32_t *)dst;\n        src2 = src;\n        for (x = 0; x < r->w; x++)\n            *(dst2++) = pal[*(src2++)];\n        dst += dst_linesize;\n        src += r->linesize[0];\n    }\n}\n\nstatic void sub2video_push_ref(InputStream *ist, int64_t pts)\n{\n    AVFrame *frame = ist->sub2video.frame;\n    int i;\n    int ret;\n\n    av_assert1(frame->data[0]);\n    ist->sub2video.last_pts = frame->pts = pts;\n    for (i = 0; i < ist->nb_filters; i++) {\n        ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame,\n                                           AV_BUFFERSRC_FLAG_KEEP_REF |\n                                           AV_BUFFERSRC_FLAG_PUSH);\n        if (ret != AVERROR_EOF && ret < 0)\n            av_log(NULL, AV_LOG_WARNING, \"Error while add the frame to buffer source(%s).\\n\",\n                   av_err2str(ret));\n    }\n}\n\nvoid sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub)\n{\n    AVFrame *frame = ist->sub2video.frame;\n    int8_t *dst;\n    int     dst_linesize;\n    int num_rects, i;\n    int64_t pts, end_pts;\n\n    if (!frame)\n        return;\n    if (sub) {\n        pts       = av_rescale_q(sub->pts + sub->start_display_time * 1000LL,\n                                 AV_TIME_BASE_Q, ist->st->time_base);\n        end_pts   = av_rescale_q(sub->pts + sub->end_display_time   * 1000LL,\n                                 AV_TIME_BASE_Q, ist->st->time_base);\n        num_rects = sub->num_rects;\n    } else {\n        /* If we are initializing the system, utilize current heartbeat\n           PTS as the start time, and show until the following subpicture\n           is received. Otherwise, utilize the previous subpicture's end time\n           as the fall-back value. */\n        pts       = ist->sub2video.initialize ?\n                    heartbeat_pts : ist->sub2video.end_pts;\n        end_pts   = INT64_MAX;\n        num_rects = 0;\n    }\n    if (sub2video_get_blank_frame(ist) < 0) {\n        av_log(ist->dec_ctx, AV_LOG_ERROR,\n               \"Impossible to get a blank canvas.\\n\");\n        return;\n    }\n    dst          = frame->data    [0];\n    dst_linesize = frame->linesize[0];\n    for (i = 0; i < num_rects; i++)\n        sub2video_copy_rect(dst, dst_linesize, frame->width, frame->height, sub->rects[i]);\n    sub2video_push_ref(ist, pts);\n    ist->sub2video.end_pts = end_pts;\n    ist->sub2video.initialize = 0;\n}\n\nstatic void sub2video_heartbeat(InputStream *ist, int64_t pts)\n{\n    InputFile *infile = input_files[ist->file_index];\n    int i, j, nb_reqs;\n    int64_t pts2;\n\n    /* When a frame is read from a file, examine all sub2video streams in\n       the same file and send the sub2video frame again. Otherwise, decoded\n       video frames could be accumulating in the filter graph while a filter\n       (possibly overlay) is desperately waiting for a subtitle frame. */\n    for (i = 0; i < infile->nb_streams; i++) {\n        InputStream *ist2 = input_streams[infile->ist_index + i];\n        if (!ist2->sub2video.frame)\n            continue;\n        /* subtitles seem to be usually muxed ahead of other streams;\n           if not, subtracting a larger time here is necessary */\n        pts2 = av_rescale_q(pts, ist->st->time_base, ist2->st->time_base) - 1;\n        /* do not send the heartbeat frame if the subtitle is already ahead */\n        if (pts2 <= ist2->sub2video.last_pts)\n            continue;\n        if (pts2 >= ist2->sub2video.end_pts || ist2->sub2video.initialize)\n            /* if we have hit the end of the current displayed subpicture,\n               or if we need to initialize the system, update the\n               overlayed subpicture and its start/end times */\n            sub2video_update(ist2, pts2 + 1, NULL);\n        for (j = 0, nb_reqs = 0; j < ist2->nb_filters; j++)\n            nb_reqs += av_buffersrc_get_nb_failed_requests(ist2->filters[j]->filter);\n        if (nb_reqs)\n            sub2video_push_ref(ist2, pts2);\n    }\n}\n\nstatic void sub2video_flush(InputStream *ist)\n{\n    int i;\n    int ret;\n\n    if (ist->sub2video.end_pts < INT64_MAX)\n        sub2video_update(ist, INT64_MAX, NULL);\n    for (i = 0; i < ist->nb_filters; i++) {\n        ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL);\n        if (ret != AVERROR_EOF && ret < 0)\n            av_log(NULL, AV_LOG_WARNING, \"Flush the frame error.\\n\");\n    }\n}\n\n/* end of sub2video hack */\n\nstatic void term_exit_sigsafe(void)\n{\n#if HAVE_TERMIOS_H\n    if(restore_tty)\n        tcsetattr (0, TCSANOW, &oldtty);\n#endif\n}\n\nvoid term_exit(void)\n{\n    av_log(NULL, AV_LOG_QUIET, \"%s\", \"\");\n    term_exit_sigsafe();\n}\n\nstatic volatile int received_sigterm = 0;\nstatic volatile int received_nb_signals = 0;\nstatic atomic_int transcode_init_done = ATOMIC_VAR_INIT(0);\nstatic volatile int ffmpeg_exited = 0;\nint main_return_code = 0;\nstatic int64_t copy_ts_first_pts = AV_NOPTS_VALUE;\n\nstatic void\nsigterm_handler(int sig)\n{\n    int ret;\n    received_sigterm = sig;\n    received_nb_signals++;\n    term_exit_sigsafe();\n    if(received_nb_signals > 3) {\n        ret = write(2/*STDERR_FILENO*/, \"Received > 3 system signals, hard exiting\\n\",\n                    strlen(\"Received > 3 system signals, hard exiting\\n\"));\n        if (ret < 0) { /* Do nothing */ };\n        exit(123);\n    }\n}\n\n#if HAVE_SETCONSOLECTRLHANDLER\nstatic BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)\n{\n    av_log(NULL, AV_LOG_DEBUG, \"\\nReceived windows signal %ld\\n\", fdwCtrlType);\n\n    switch (fdwCtrlType)\n    {\n    case CTRL_C_EVENT:\n    case CTRL_BREAK_EVENT:\n        sigterm_handler(SIGINT);\n        return TRUE;\n\n    case CTRL_CLOSE_EVENT:\n    case CTRL_LOGOFF_EVENT:\n    case CTRL_SHUTDOWN_EVENT:\n        sigterm_handler(SIGTERM);\n        /* Basically, with these 3 events, when we return from this method the\n           process is hard terminated, so stall as long as we need to\n           to try and let the main thread(s) clean up and gracefully terminate\n           (we have at most 5 seconds, but should be done far before that). */\n        while (!ffmpeg_exited) {\n            Sleep(0);\n        }\n        return TRUE;\n\n    default:\n        av_log(NULL, AV_LOG_ERROR, \"Received unknown windows signal %ld\\n\", fdwCtrlType);\n        return FALSE;\n    }\n}\n#endif\n\n#ifdef __linux__\n#define SIGNAL(sig, func)               \\\n    do {                                \\\n        action.sa_handler = func;       \\\n        sigaction(sig, &action, NULL);  \\\n    } while (0)\n#else\n#define SIGNAL(sig, func) \\\n    signal(sig, func)\n#endif\n\nvoid term_init(void)\n{\n#if defined __linux__\n    struct sigaction action = {0};\n    action.sa_handler = sigterm_handler;\n\n    /* block other interrupts while processing this one */\n    sigfillset(&action.sa_mask);\n\n    /* restart interruptible functions (i.e. don't fail with EINTR)  */\n    action.sa_flags = SA_RESTART;\n#endif\n\n#if HAVE_TERMIOS_H\n    if (stdin_interaction) {\n        struct termios tty;\n        if (tcgetattr (0, &tty) == 0) {\n            oldtty = tty;\n            restore_tty = 1;\n\n            tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP\n                             |INLCR|IGNCR|ICRNL|IXON);\n            tty.c_oflag |= OPOST;\n            tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);\n            tty.c_cflag &= ~(CSIZE|PARENB);\n            tty.c_cflag |= CS8;\n            tty.c_cc[VMIN] = 1;\n            tty.c_cc[VTIME] = 0;\n\n            tcsetattr (0, TCSANOW, &tty);\n        }\n        SIGNAL(SIGQUIT, sigterm_handler); /* Quit (POSIX).  */\n    }\n#endif\n\n    SIGNAL(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */\n    SIGNAL(SIGTERM, sigterm_handler); /* Termination (ANSI).  */\n#ifdef SIGXCPU\n    SIGNAL(SIGXCPU, sigterm_handler);\n#endif\n#ifdef SIGPIPE\n    signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */\n#endif\n#if HAVE_SETCONSOLECTRLHANDLER\n    SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);\n#endif\n}\n\n/* read a key without blocking */\nstatic int read_key(void)\n{\n    unsigned char ch;\n#if HAVE_TERMIOS_H\n    int n = 1;\n    struct timeval tv;\n    fd_set rfds;\n\n    FD_ZERO(&rfds);\n    FD_SET(0, &rfds);\n    tv.tv_sec = 0;\n    tv.tv_usec = 0;\n    n = select(1, &rfds, NULL, NULL, &tv);\n    if (n > 0) {\n        n = read(0, &ch, 1);\n        if (n == 1)\n            return ch;\n\n        return n;\n    }\n#elif HAVE_KBHIT\n#    if HAVE_PEEKNAMEDPIPE\n    static int is_pipe;\n    static HANDLE input_handle;\n    DWORD dw, nchars;\n    if(!input_handle){\n        input_handle = GetStdHandle(STD_INPUT_HANDLE);\n        is_pipe = !GetConsoleMode(input_handle, &dw);\n    }\n\n    if (is_pipe) {\n        /* When running under a GUI, you will end here. */\n        if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL)) {\n            // input pipe may have been closed by the program that ran ffmpeg\n            return -1;\n        }\n        //Read it\n        if(nchars != 0) {\n            read(0, &ch, 1);\n            return ch;\n        }else{\n            return -1;\n        }\n    }\n#    endif\n    if(kbhit())\n        return(getch());\n#endif\n    return -1;\n}\n\nstatic int decode_interrupt_cb(void *ctx)\n{\n    return received_nb_signals > atomic_load(&transcode_init_done);\n}\n\nconst AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };\n\nstatic void ffmpeg_cleanup(int ret)\n{\n    int i, j;\n\n    if (do_benchmark) {\n        int maxrss = getmaxrss() / 1024;\n        av_log(NULL, AV_LOG_INFO, \"bench: maxrss=%ikB\\n\", maxrss);\n    }\n\n    for (i = 0; i < nb_filtergraphs; i++) {\n        FilterGraph *fg = filtergraphs[i];\n        avfilter_graph_free(&fg->graph);\n        for (j = 0; j < fg->nb_inputs; j++) {\n            InputFilter *ifilter = fg->inputs[j];\n            struct InputStream *ist = ifilter->ist;\n\n            if (ifilter->frame_queue) {\n                AVFrame *frame;\n                while (av_fifo_read(ifilter->frame_queue, &frame, 1) >= 0)\n                    av_frame_free(&frame);\n                av_fifo_freep2(&ifilter->frame_queue);\n            }\n            av_freep(&ifilter->displaymatrix);\n            if (ist->sub2video.sub_queue) {\n                AVSubtitle sub;\n                while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)\n                    avsubtitle_free(&sub);\n                av_fifo_freep2(&ist->sub2video.sub_queue);\n            }\n            av_buffer_unref(&ifilter->hw_frames_ctx);\n            av_freep(&ifilter->name);\n            av_freep(&fg->inputs[j]);\n        }\n        av_freep(&fg->inputs);\n        for (j = 0; j < fg->nb_outputs; j++) {\n            OutputFilter *ofilter = fg->outputs[j];\n\n            avfilter_inout_free(&ofilter->out_tmp);\n            av_freep(&ofilter->name);\n            av_channel_layout_uninit(&ofilter->ch_layout);\n            av_freep(&fg->outputs[j]);\n        }\n        av_freep(&fg->outputs);\n        av_freep(&fg->graph_desc);\n\n        av_freep(&filtergraphs[i]);\n    }\n    av_freep(&filtergraphs);\n\n    av_freep(&subtitle_out);\n\n    /* close files */\n    for (i = 0; i < nb_output_files; i++)\n        of_close(&output_files[i]);\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n\n        if (!ost)\n            continue;\n\n        av_bsf_free(&ost->bsf_ctx);\n\n        av_frame_free(&ost->filtered_frame);\n        av_frame_free(&ost->last_frame);\n        av_packet_free(&ost->pkt);\n        av_dict_free(&ost->encoder_opts);\n\n        av_freep(&ost->forced_keyframes);\n        av_expr_free(ost->forced_keyframes_pexpr);\n        av_freep(&ost->avfilter);\n        av_freep(&ost->logfile_prefix);\n\n        av_freep(&ost->audio_channels_map);\n        ost->audio_channels_mapped = 0;\n\n        av_dict_free(&ost->sws_dict);\n        av_dict_free(&ost->swr_opts);\n\n        avcodec_free_context(&ost->enc_ctx);\n        avcodec_parameters_free(&ost->ref_par);\n\n        if (ost->muxing_queue) {\n            AVPacket *pkt;\n            while (av_fifo_read(ost->muxing_queue, &pkt, 1) >= 0)\n                av_packet_free(&pkt);\n            av_fifo_freep2(&ost->muxing_queue);\n        }\n\n        av_freep(&output_streams[i]);\n    }\n#if HAVE_THREADS\n    free_input_threads();\n#endif\n    for (i = 0; i < nb_input_files; i++) {\n        avformat_close_input(&input_files[i]->ctx);\n        av_packet_free(&input_files[i]->pkt);\n        av_freep(&input_files[i]);\n    }\n    for (i = 0; i < nb_input_streams; i++) {\n        InputStream *ist = input_streams[i];\n\n        av_frame_free(&ist->decoded_frame);\n        av_packet_free(&ist->pkt);\n        av_dict_free(&ist->decoder_opts);\n        avsubtitle_free(&ist->prev_sub.subtitle);\n        av_frame_free(&ist->sub2video.frame);\n        av_freep(&ist->filters);\n        av_freep(&ist->hwaccel_device);\n        av_freep(&ist->dts_buffer);\n\n        avcodec_free_context(&ist->dec_ctx);\n\n        av_freep(&input_streams[i]);\n    }\n\n    if (vstats_file) {\n        if (fclose(vstats_file))\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Error closing vstats file, loss of information possible: %s\\n\",\n                   av_err2str(AVERROR(errno)));\n    }\n    av_freep(&vstats_filename);\n    av_freep(&filter_nbthreads);\n\n    av_freep(&input_streams);\n    av_freep(&input_files);\n    av_freep(&output_streams);\n    av_freep(&output_files);\n\n    uninit_opts();\n\n    avformat_network_deinit();\n\n    if (received_sigterm) {\n        av_log(NULL, AV_LOG_INFO, \"Exiting normally, received signal %d.\\n\",\n               (int) received_sigterm);\n    } else if (ret && atomic_load(&transcode_init_done)) {\n        av_log(NULL, AV_LOG_INFO, \"Conversion failed!\\n\");\n    }\n    term_exit();\n    ffmpeg_exited = 1;\n}\n\nvoid remove_avoptions(AVDictionary **a, AVDictionary *b)\n{\n    const AVDictionaryEntry *t = NULL;\n\n    while ((t = av_dict_get(b, \"\", t, AV_DICT_IGNORE_SUFFIX))) {\n        av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE);\n    }\n}\n\nvoid assert_avoptions(AVDictionary *m)\n{\n    const AVDictionaryEntry *t;\n    if ((t = av_dict_get(m, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(NULL, AV_LOG_FATAL, \"Option %s not found.\\n\", t->key);\n        exit_program(1);\n    }\n}\n\nstatic void abort_codec_experimental(const AVCodec *c, int encoder)\n{\n    exit_program(1);\n}\n\nstatic void update_benchmark(const char *fmt, ...)\n{\n    if (do_benchmark_all) {\n        BenchmarkTimeStamps t = get_benchmark_time_stamps();\n        va_list va;\n        char buf[1024];\n\n        if (fmt) {\n            va_start(va, fmt);\n            vsnprintf(buf, sizeof(buf), fmt, va);\n            va_end(va);\n            av_log(NULL, AV_LOG_INFO,\n                   \"bench: %8\" PRIu64 \" user %8\" PRIu64 \" sys %8\" PRIu64 \" real %s \\n\",\n                   t.user_usec - current_time.user_usec,\n                   t.sys_usec - current_time.sys_usec,\n                   t.real_usec - current_time.real_usec, buf);\n        }\n        current_time = t;\n    }\n}\n\nstatic void close_output_stream(OutputStream *ost)\n{\n    OutputFile *of = output_files[ost->file_index];\n    AVRational time_base = ost->stream_copy ? ost->mux_timebase : ost->enc_ctx->time_base;\n\n    ost->finished |= ENCODER_FINISHED;\n    if (of->shortest) {\n        int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, time_base, AV_TIME_BASE_Q);\n        of->recording_time = FFMIN(of->recording_time, end);\n    }\n}\n\n/*\n * Send a single packet to the output, applying any bitstream filters\n * associated with the output stream.  This may result in any number\n * of packets actually being written, depending on what bitstream\n * filters are applied.  The supplied packet is consumed and will be\n * blank (as if newly-allocated) when this function returns.\n *\n * If eof is set, instead indicate EOF to all bitstream filters and\n * therefore flush any delayed packets to the output.  A blank packet\n * must be supplied in this case.\n */\nstatic void output_packet(OutputFile *of, AVPacket *pkt,\n                          OutputStream *ost, int eof)\n{\n    int ret = 0;\n\n    /* apply the output bitstream filters */\n    if (ost->bsf_ctx) {\n        ret = av_bsf_send_packet(ost->bsf_ctx, eof ? NULL : pkt);\n        if (ret < 0)\n            goto finish;\n        while ((ret = av_bsf_receive_packet(ost->bsf_ctx, pkt)) >= 0)\n            of_write_packet(of, pkt, ost, 0);\n        if (ret == AVERROR(EAGAIN))\n            ret = 0;\n    } else if (!eof)\n        of_write_packet(of, pkt, ost, 0);\n\nfinish:\n    if (ret < 0 && ret != AVERROR_EOF) {\n        av_log(NULL, AV_LOG_ERROR, \"Error applying bitstream filters to an output \"\n               \"packet for stream #%d:%d.\\n\", ost->file_index, ost->index);\n        if(exit_on_error)\n            exit_program(1);\n    }\n}\n\nstatic int check_recording_time(OutputStream *ost)\n{\n    OutputFile *of = output_files[ost->file_index];\n\n    if (of->recording_time != INT64_MAX &&\n        av_compare_ts(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, of->recording_time,\n                      AV_TIME_BASE_Q) >= 0) {\n        close_output_stream(ost);\n        return 0;\n    }\n    return 1;\n}\n\nstatic double adjust_frame_pts_to_encoder_tb(OutputFile *of, OutputStream *ost,\n                                             AVFrame *frame)\n{\n    double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but with higher precision\n    AVCodecContext *enc = ost->enc_ctx;\n    if (!frame || frame->pts == AV_NOPTS_VALUE ||\n        !enc || !ost->filter || !ost->filter->graph->graph)\n        goto early_exit;\n\n    {\n        AVFilterContext *filter = ost->filter->filter;\n\n        int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;\n        AVRational filter_tb = av_buffersink_get_time_base(filter);\n        AVRational tb = enc->time_base;\n        int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16);\n\n        tb.den <<= extra_bits;\n        float_pts =\n            av_rescale_q(frame->pts, filter_tb, tb) -\n            av_rescale_q(start_time, AV_TIME_BASE_Q, tb);\n        float_pts /= 1 << extra_bits;\n        // avoid exact midoints to reduce the chance of rounding differences, this can be removed in case the fps code is changed to work with integers\n        float_pts += FFSIGN(float_pts) * 1.0 / (1<<17);\n\n        frame->pts =\n            av_rescale_q(frame->pts, filter_tb, enc->time_base) -\n            av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);\n    }\n\nearly_exit:\n\n    if (debug_ts) {\n        av_log(NULL, AV_LOG_INFO, \"filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\\n\",\n               frame ? av_ts2str(frame->pts) : \"NULL\",\n               frame ? av_ts2timestr(frame->pts, &enc->time_base) : \"NULL\",\n               float_pts,\n               enc ? enc->time_base.num : -1,\n               enc ? enc->time_base.den : -1);\n    }\n\n    return float_pts;\n}\n\nstatic int init_output_stream(OutputStream *ost, AVFrame *frame,\n                              char *error, int error_len);\n\nstatic int init_output_stream_wrapper(OutputStream *ost, AVFrame *frame,\n                                      unsigned int fatal)\n{\n    int ret = AVERROR_BUG;\n    char error[1024] = {0};\n\n    if (ost->initialized)\n        return 0;\n\n    ret = init_output_stream(ost, frame, error, sizeof(error));\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Error initializing output stream %d:%d -- %s\\n\",\n               ost->file_index, ost->index, error);\n\n        if (fatal)\n            exit_program(1);\n    }\n\n    return ret;\n}\n\nstatic double psnr(double d)\n{\n    return -10.0 * log10(d);\n}\n\nstatic void update_video_stats(OutputStream *ost, const AVPacket *pkt, int write_vstats)\n{\n    const uint8_t *sd = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,\n                                                NULL);\n    AVCodecContext *enc = ost->enc_ctx;\n    int64_t frame_number;\n    double ti1, bitrate, avg_bitrate;\n\n    ost->quality   = sd ? AV_RL32(sd) : -1;\n    ost->pict_type = sd ? sd[4] : AV_PICTURE_TYPE_NONE;\n\n    for (int i = 0; i<FF_ARRAY_ELEMS(ost->error); i++) {\n        if (sd && i < sd[5])\n            ost->error[i] = AV_RL64(sd + 8 + 8*i);\n        else\n            ost->error[i] = -1;\n    }\n\n    if (!write_vstats)\n        return;\n\n    /* this is executed just the first time update_video_stats is called */\n    if (!vstats_file) {\n        vstats_file = fopen(vstats_filename, \"w\");\n        if (!vstats_file) {\n            perror(\"fopen\");\n            exit_program(1);\n        }\n    }\n\n    frame_number = ost->packets_encoded;\n    if (vstats_version <= 1) {\n        fprintf(vstats_file, \"frame= %5\"PRId64\" q= %2.1f \", frame_number,\n                ost->quality / (float)FF_QP2LAMBDA);\n    } else  {\n        fprintf(vstats_file, \"out= %2d st= %2d frame= %5\"PRId64\" q= %2.1f \", ost->file_index, ost->index, frame_number,\n                ost->quality / (float)FF_QP2LAMBDA);\n    }\n\n    if (ost->error[0]>=0 && (enc->flags & AV_CODEC_FLAG_PSNR))\n        fprintf(vstats_file, \"PSNR= %6.2f \", psnr(ost->error[0] / (enc->width * enc->height * 255.0 * 255.0)));\n\n    fprintf(vstats_file,\"f_size= %6d \", pkt->size);\n    /* compute pts value */\n    ti1 = pkt->dts * av_q2d(ost->mux_timebase);\n    if (ti1 < 0.01)\n        ti1 = 0.01;\n\n    bitrate     = (pkt->size * 8) / av_q2d(enc->time_base) / 1000.0;\n    avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0;\n    fprintf(vstats_file, \"s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s \",\n           (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate);\n    fprintf(vstats_file, \"type= %c\\n\", av_get_picture_type_char(ost->pict_type));\n}\n\nstatic int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame)\n{\n    AVCodecContext   *enc = ost->enc_ctx;\n    AVPacket         *pkt = ost->pkt;\n    const char *type_desc = av_get_media_type_string(enc->codec_type);\n    const char    *action = frame ? \"encode\" : \"flush\";\n    int ret;\n\n    if (frame) {\n        ost->frames_encoded++;\n\n        if (debug_ts) {\n            av_log(NULL, AV_LOG_INFO, \"encoder <- type:%s \"\n                   \"frame_pts:%s frame_pts_time:%s time_base:%d/%d\\n\",\n                   type_desc,\n                   av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base),\n                   enc->time_base.num, enc->time_base.den);\n        }\n    }\n\n    update_benchmark(NULL);\n\n    ret = avcodec_send_frame(enc, frame);\n    if (ret < 0 && !(ret == AVERROR_EOF && !frame)) {\n        av_log(NULL, AV_LOG_ERROR, \"Error submitting %s frame to the encoder\\n\",\n               type_desc);\n        return ret;\n    }\n\n    while (1) {\n        ret = avcodec_receive_packet(enc, pkt);\n        update_benchmark(\"%s_%s %d.%d\", action, type_desc,\n                         ost->file_index, ost->index);\n\n        /* if two pass, output log on success and EOF */\n        if ((ret >= 0 || ret == AVERROR_EOF) && ost->logfile && enc->stats_out)\n            fprintf(ost->logfile, \"%s\", enc->stats_out);\n\n        if (ret == AVERROR(EAGAIN)) {\n            av_assert0(frame); // should never happen during flushing\n            return 0;\n        } else if (ret == AVERROR_EOF) {\n            output_packet(of, pkt, ost, 1);\n            return ret;\n        } else if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"%s encoding failed\\n\", type_desc);\n            return ret;\n        }\n\n        if (debug_ts) {\n            av_log(NULL, AV_LOG_INFO, \"encoder -> type:%s \"\n                   \"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s \"\n                   \"duration:%s duration_time:%s\\n\",\n                   type_desc,\n                   av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base),\n                   av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base),\n                   av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));\n        }\n\n        av_packet_rescale_ts(pkt, enc->time_base, ost->mux_timebase);\n\n        if (debug_ts) {\n            av_log(NULL, AV_LOG_INFO, \"encoder -> type:%s \"\n                   \"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s \"\n                   \"duration:%s duration_time:%s\\n\",\n                   type_desc,\n                   av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &enc->time_base),\n                   av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &enc->time_base),\n                   av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));\n        }\n\n        if (enc->codec_type == AVMEDIA_TYPE_VIDEO)\n            update_video_stats(ost, pkt, !!vstats_filename);\n\n        ost->packets_encoded++;\n\n        output_packet(of, pkt, ost, 0);\n    }\n\n    av_assert0(0);\n}\n\nstatic void do_audio_out(OutputFile *of, OutputStream *ost,\n                         AVFrame *frame)\n{\n    int ret;\n\n    adjust_frame_pts_to_encoder_tb(of, ost, frame);\n\n    if (!check_recording_time(ost))\n        return;\n\n    if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)\n        frame->pts = ost->sync_opts;\n    ost->sync_opts = frame->pts + frame->nb_samples;\n    ost->samples_encoded += frame->nb_samples;\n\n    ret = encode_frame(of, ost, frame);\n    if (ret < 0)\n        exit_program(1);\n}\n\nstatic void do_subtitle_out(OutputFile *of,\n                            OutputStream *ost,\n                            AVSubtitle *sub)\n{\n    int subtitle_out_max_size = 1024 * 1024;\n    int subtitle_out_size, nb, i;\n    AVCodecContext *enc;\n    AVPacket *pkt = ost->pkt;\n    int64_t pts;\n\n    if (sub->pts == AV_NOPTS_VALUE) {\n        av_log(NULL, AV_LOG_ERROR, \"Subtitle packets must have a pts\\n\");\n        if (exit_on_error)\n            exit_program(1);\n        return;\n    }\n\n    enc = ost->enc_ctx;\n\n    if (!subtitle_out) {\n        subtitle_out = av_malloc(subtitle_out_max_size);\n        if (!subtitle_out) {\n            av_log(NULL, AV_LOG_FATAL, \"Failed to allocate subtitle_out\\n\");\n            exit_program(1);\n        }\n    }\n\n    /* Note: DVB subtitle need one packet to draw them and one other\n       packet to clear them */\n    /* XXX: signal it in the codec context ? */\n    if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE)\n        nb = 2;\n    else\n        nb = 1;\n\n    /* shift timestamp to honor -ss and make check_recording_time() work with -t */\n    pts = sub->pts;\n    if (output_files[ost->file_index]->start_time != AV_NOPTS_VALUE)\n        pts -= output_files[ost->file_index]->start_time;\n    for (i = 0; i < nb; i++) {\n        unsigned save_num_rects = sub->num_rects;\n\n        ost->sync_opts = av_rescale_q(pts, AV_TIME_BASE_Q, enc->time_base);\n        if (!check_recording_time(ost))\n            return;\n\n        sub->pts = pts;\n        // start_display_time is required to be 0\n        sub->pts               += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);\n        sub->end_display_time  -= sub->start_display_time;\n        sub->start_display_time = 0;\n        if (i == 1)\n            sub->num_rects = 0;\n\n        ost->frames_encoded++;\n\n        subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,\n                                                    subtitle_out_max_size, sub);\n        if (i == 1)\n            sub->num_rects = save_num_rects;\n        if (subtitle_out_size < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Subtitle encoding failed\\n\");\n            exit_program(1);\n        }\n\n        av_packet_unref(pkt);\n        pkt->data = subtitle_out;\n        pkt->size = subtitle_out_size;\n        pkt->pts  = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->mux_timebase);\n        pkt->duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->mux_timebase);\n        if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {\n            /* XXX: the pts correction is handled here. Maybe handling\n               it in the codec would be better */\n            if (i == 0)\n                pkt->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, ost->mux_timebase);\n            else\n                pkt->pts += av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->mux_timebase);\n        }\n        pkt->dts = pkt->pts;\n        output_packet(of, pkt, ost, 0);\n    }\n}\n\n/* May modify/reset next_picture */\nstatic void do_video_out(OutputFile *of,\n                         OutputStream *ost,\n                         AVFrame *next_picture)\n{\n    int ret;\n    AVCodecContext *enc = ost->enc_ctx;\n    AVRational frame_rate;\n    int64_t nb_frames, nb0_frames, i;\n    double delta, delta0;\n    double duration = 0;\n    double sync_ipts = AV_NOPTS_VALUE;\n    InputStream *ist = NULL;\n    AVFilterContext *filter = ost->filter->filter;\n\n    init_output_stream_wrapper(ost, next_picture, 1);\n    sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, next_picture);\n\n    if (ost->source_index >= 0)\n        ist = input_streams[ost->source_index];\n\n    frame_rate = av_buffersink_get_frame_rate(filter);\n    if (frame_rate.num > 0 && frame_rate.den > 0)\n        duration = 1/(av_q2d(frame_rate) * av_q2d(enc->time_base));\n\n    if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)\n        duration = FFMIN(duration, 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base)));\n\n    if (!ost->filters_script &&\n        !ost->filters &&\n        (nb_filtergraphs == 0 || !filtergraphs[0]->graph_desc) &&\n        next_picture &&\n        ist &&\n        lrintf(next_picture->pkt_duration * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) {\n        duration = lrintf(next_picture->pkt_duration * av_q2d(ist->st->time_base) / av_q2d(enc->time_base));\n    }\n\n    if (!next_picture) {\n        //end, flushing\n        nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],\n                                          ost->last_nb0_frames[1],\n                                          ost->last_nb0_frames[2]);\n    } else {\n        delta0 = sync_ipts - ost->sync_opts; // delta0 is the \"drift\" between the input frame (next_picture) and where it would fall in the output.\n        delta  = delta0 + duration;\n\n        /* by default, we output a single frame */\n        nb0_frames = 0; // tracks the number of times the PREVIOUS frame should be duplicated, mostly for variable framerate (VFR)\n        nb_frames = 1;\n\n        if (delta0 < 0 &&\n            delta > 0 &&\n            ost->vsync_method != VSYNC_PASSTHROUGH &&\n            ost->vsync_method != VSYNC_DROP) {\n            if (delta0 < -0.6) {\n                av_log(NULL, AV_LOG_VERBOSE, \"Past duration %f too large\\n\", -delta0);\n            } else\n                av_log(NULL, AV_LOG_DEBUG, \"Clipping frame in rate conversion by %f\\n\", -delta0);\n            sync_ipts = ost->sync_opts;\n            duration += delta0;\n            delta0 = 0;\n        }\n\n        switch (ost->vsync_method) {\n        case VSYNC_VSCFR:\n            if (ost->frame_number == 0 && delta0 >= 0.5) {\n                av_log(NULL, AV_LOG_DEBUG, \"Not duplicating %d initial frames\\n\", (int)lrintf(delta0));\n                delta = duration;\n                delta0 = 0;\n                ost->sync_opts = llrint(sync_ipts);\n            }\n        case VSYNC_CFR:\n            // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c\n            if (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) {\n                nb_frames = 0;\n            } else if (delta < -1.1)\n                nb_frames = 0;\n            else if (delta > 1.1) {\n                nb_frames = llrintf(delta);\n                if (delta0 > 1.1)\n                    nb0_frames = llrintf(delta0 - 0.6);\n            }\n            break;\n        case VSYNC_VFR:\n            if (delta <= -0.6)\n                nb_frames = 0;\n            else if (delta > 0.6)\n                ost->sync_opts = llrint(sync_ipts);\n            break;\n        case VSYNC_DROP:\n        case VSYNC_PASSTHROUGH:\n            ost->sync_opts = llrint(sync_ipts);\n            break;\n        default:\n            av_assert0(0);\n        }\n    }\n\n    /*\n     * For video, number of frames in == number of packets out.\n     * But there may be reordering, so we can't throw away frames on encoder\n     * flush, we need to limit them here, before they go into encoder.\n     */\n    nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);\n    nb0_frames = FFMIN(nb0_frames, nb_frames);\n\n    memmove(ost->last_nb0_frames + 1,\n            ost->last_nb0_frames,\n            sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1));\n    ost->last_nb0_frames[0] = nb0_frames;\n\n    if (nb0_frames == 0 && ost->last_dropped) {\n        nb_frames_drop++;\n        av_log(NULL, AV_LOG_VERBOSE,\n               \"*** dropping frame %\"PRId64\" from stream %d at ts %\"PRId64\"\\n\",\n               ost->frame_number, ost->st->index, ost->last_frame->pts);\n    }\n    if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) {\n        if (nb_frames > dts_error_threshold * 30) {\n            av_log(NULL, AV_LOG_ERROR, \"%\"PRId64\" frame duplication too large, skipping\\n\", nb_frames - 1);\n            nb_frames_drop++;\n            return;\n        }\n        nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames);\n        av_log(NULL, AV_LOG_VERBOSE, \"*** %\"PRId64\" dup!\\n\", nb_frames - 1);\n        if (nb_frames_dup > dup_warning) {\n            av_log(NULL, AV_LOG_WARNING, \"More than %\"PRIu64\" frames duplicated\\n\", dup_warning);\n            dup_warning *= 10;\n        }\n    }\n    ost->last_dropped = nb_frames == nb0_frames && next_picture;\n    ost->dropped_keyframe = ost->last_dropped && next_picture && next_picture->key_frame;\n\n    /* duplicates frame if needed */\n    for (i = 0; i < nb_frames; i++) {\n        AVFrame *in_picture;\n        int forced_keyframe = 0;\n        double pts_time;\n\n        if (i < nb0_frames && ost->last_frame->buf[0]) {\n            in_picture = ost->last_frame;\n        } else\n            in_picture = next_picture;\n\n        if (!in_picture)\n            return;\n\n        in_picture->pts = ost->sync_opts;\n\n        if (!check_recording_time(ost))\n            return;\n\n        in_picture->quality = enc->global_quality;\n        in_picture->pict_type = 0;\n\n        if (ost->forced_kf_ref_pts == AV_NOPTS_VALUE &&\n            in_picture->pts != AV_NOPTS_VALUE)\n            ost->forced_kf_ref_pts = in_picture->pts;\n\n        pts_time = in_picture->pts != AV_NOPTS_VALUE ?\n            (in_picture->pts - ost->forced_kf_ref_pts) * av_q2d(enc->time_base) : NAN;\n        if (ost->forced_kf_index < ost->forced_kf_count &&\n            in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {\n            ost->forced_kf_index++;\n            forced_keyframe = 1;\n        } else if (ost->forced_keyframes_pexpr) {\n            double res;\n            ost->forced_keyframes_expr_const_values[FKF_T] = pts_time;\n            res = av_expr_eval(ost->forced_keyframes_pexpr,\n                               ost->forced_keyframes_expr_const_values, NULL);\n            ff_dlog(NULL, \"force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\\n\",\n                    ost->forced_keyframes_expr_const_values[FKF_N],\n                    ost->forced_keyframes_expr_const_values[FKF_N_FORCED],\n                    ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],\n                    ost->forced_keyframes_expr_const_values[FKF_T],\n                    ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],\n                    res);\n            if (res) {\n                forced_keyframe = 1;\n                ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] =\n                    ost->forced_keyframes_expr_const_values[FKF_N];\n                ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] =\n                    ost->forced_keyframes_expr_const_values[FKF_T];\n                ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1;\n            }\n\n            ost->forced_keyframes_expr_const_values[FKF_N] += 1;\n        } else if (   ost->forced_keyframes\n                   && !strncmp(ost->forced_keyframes, \"source\", 6)\n                   && in_picture->key_frame==1\n                   && !i) {\n            forced_keyframe = 1;\n        } else if (   ost->forced_keyframes\n                   && !strncmp(ost->forced_keyframes, \"source_no_drop\", 14)\n                   && !i) {\n            forced_keyframe = (in_picture->key_frame == 1) || ost->dropped_keyframe;\n            ost->dropped_keyframe = 0;\n        }\n\n        if (forced_keyframe) {\n            in_picture->pict_type = AV_PICTURE_TYPE_I;\n            av_log(NULL, AV_LOG_DEBUG, \"Forced keyframe at time %f\\n\", pts_time);\n        }\n\n        ret = encode_frame(of, ost, in_picture);\n        if (ret < 0)\n            exit_program(1);\n\n        ost->sync_opts++;\n        ost->frame_number++;\n    }\n\n    av_frame_unref(ost->last_frame);\n    if (next_picture)\n        av_frame_move_ref(ost->last_frame, next_picture);\n}\n\nstatic void finish_output_stream(OutputStream *ost)\n{\n    OutputFile *of = output_files[ost->file_index];\n    AVRational time_base = ost->stream_copy ? ost->mux_timebase : ost->enc_ctx->time_base;\n\n    ost->finished = ENCODER_FINISHED | MUXER_FINISHED;\n\n    if (of->shortest) {\n        int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, time_base, AV_TIME_BASE_Q);\n        of->recording_time = FFMIN(of->recording_time, end);\n    }\n}\n\n/**\n * Get and encode new output from any of the filtergraphs, without causing\n * activity.\n *\n * @return  0 for success, <0 for severe errors\n */\nstatic int reap_filters(int flush)\n{\n    AVFrame *filtered_frame = NULL;\n    int i;\n\n    /* Reap all buffers present in the buffer sinks */\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n        OutputFile    *of = output_files[ost->file_index];\n        AVFilterContext *filter;\n        AVCodecContext *enc = ost->enc_ctx;\n        int ret = 0;\n\n        if (!ost->filter || !ost->filter->graph->graph)\n            continue;\n        filter = ost->filter->filter;\n\n        /*\n         * Unlike video, with audio the audio frame size matters.\n         * Currently we are fully reliant on the lavfi filter chain to\n         * do the buffering deed for us, and thus the frame size parameter\n         * needs to be set accordingly. Where does one get the required\n         * frame size? From the initialized AVCodecContext of an audio\n         * encoder. Thus, if we have gotten to an audio stream, initialize\n         * the encoder earlier than receiving the first AVFrame.\n         */\n        if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_AUDIO)\n            init_output_stream_wrapper(ost, NULL, 1);\n\n        filtered_frame = ost->filtered_frame;\n\n        while (1) {\n            ret = av_buffersink_get_frame_flags(filter, filtered_frame,\n                                               AV_BUFFERSINK_FLAG_NO_REQUEST);\n            if (ret < 0) {\n                if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {\n                    av_log(NULL, AV_LOG_WARNING,\n                           \"Error in av_buffersink_get_frame_flags(): %s\\n\", av_err2str(ret));\n                } else if (flush && ret == AVERROR_EOF) {\n                    if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_VIDEO)\n                        do_video_out(of, ost, NULL);\n                }\n                break;\n            }\n            if (ost->finished) {\n                av_frame_unref(filtered_frame);\n                continue;\n            }\n\n            switch (av_buffersink_get_type(filter)) {\n            case AVMEDIA_TYPE_VIDEO:\n                if (!ost->frame_aspect_ratio.num)\n                    enc->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;\n\n                do_video_out(of, ost, filtered_frame);\n                break;\n            case AVMEDIA_TYPE_AUDIO:\n                if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&\n                    enc->ch_layout.nb_channels != filtered_frame->ch_layout.nb_channels) {\n                    av_log(NULL, AV_LOG_ERROR,\n                           \"Audio filter graph output is not normalized and encoder does not support parameter changes\\n\");\n                    break;\n                }\n                do_audio_out(of, ost, filtered_frame);\n                break;\n            default:\n                // TODO support subtitle filters\n                av_assert0(0);\n            }\n\n            av_frame_unref(filtered_frame);\n        }\n    }\n\n    return 0;\n}\n\nstatic void print_final_stats(int64_t total_size)\n{\n    uint64_t video_size = 0, audio_size = 0, extra_size = 0, other_size = 0;\n    uint64_t subtitle_size = 0;\n    uint64_t data_size = 0;\n    float percent = -1.0;\n    int i, j;\n    int pass1_used = 1;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n        switch (ost->enc_ctx->codec_type) {\n            case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;\n            case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;\n            case AVMEDIA_TYPE_SUBTITLE: subtitle_size += ost->data_size; break;\n            default:                 other_size += ost->data_size; break;\n        }\n        extra_size += ost->enc_ctx->extradata_size;\n        data_size  += ost->data_size;\n        if (   (ost->enc_ctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2))\n            != AV_CODEC_FLAG_PASS1)\n            pass1_used = 0;\n    }\n\n    if (data_size && total_size>0 && total_size >= data_size)\n        percent = 100.0 * (total_size - data_size) / data_size;\n\n    av_log(NULL, AV_LOG_INFO, \"video:%1.0fkB audio:%1.0fkB subtitle:%1.0fkB other streams:%1.0fkB global headers:%1.0fkB muxing overhead: \",\n           video_size / 1024.0,\n           audio_size / 1024.0,\n           subtitle_size / 1024.0,\n           other_size / 1024.0,\n           extra_size / 1024.0);\n    if (percent >= 0.0)\n        av_log(NULL, AV_LOG_INFO, \"%f%%\", percent);\n    else\n        av_log(NULL, AV_LOG_INFO, \"unknown\");\n    av_log(NULL, AV_LOG_INFO, \"\\n\");\n\n    /* print verbose per-stream stats */\n    for (i = 0; i < nb_input_files; i++) {\n        InputFile *f = input_files[i];\n        uint64_t total_packets = 0, total_size = 0;\n\n        av_log(NULL, AV_LOG_VERBOSE, \"Input file #%d (%s):\\n\",\n               i, f->ctx->url);\n\n        for (j = 0; j < f->nb_streams; j++) {\n            InputStream *ist = input_streams[f->ist_index + j];\n            enum AVMediaType type = ist->dec_ctx->codec_type;\n\n            total_size    += ist->data_size;\n            total_packets += ist->nb_packets;\n\n            av_log(NULL, AV_LOG_VERBOSE, \"  Input stream #%d:%d (%s): \",\n                   i, j, av_get_media_type_string(type));\n            av_log(NULL, AV_LOG_VERBOSE, \"%\"PRIu64\" packets read (%\"PRIu64\" bytes); \",\n                   ist->nb_packets, ist->data_size);\n\n            if (ist->decoding_needed) {\n                av_log(NULL, AV_LOG_VERBOSE, \"%\"PRIu64\" frames decoded\",\n                       ist->frames_decoded);\n                if (type == AVMEDIA_TYPE_AUDIO)\n                    av_log(NULL, AV_LOG_VERBOSE, \" (%\"PRIu64\" samples)\", ist->samples_decoded);\n                av_log(NULL, AV_LOG_VERBOSE, \"; \");\n            }\n\n            av_log(NULL, AV_LOG_VERBOSE, \"\\n\");\n        }\n\n        av_log(NULL, AV_LOG_VERBOSE, \"  Total: %\"PRIu64\" packets (%\"PRIu64\" bytes) demuxed\\n\",\n               total_packets, total_size);\n    }\n\n    for (i = 0; i < nb_output_files; i++) {\n        OutputFile *of = output_files[i];\n        uint64_t total_packets = 0, total_size = 0;\n\n        av_log(NULL, AV_LOG_VERBOSE, \"Output file #%d (%s):\\n\",\n               i, of->ctx->url);\n\n        for (j = 0; j < of->ctx->nb_streams; j++) {\n            OutputStream *ost = output_streams[of->ost_index + j];\n            enum AVMediaType type = ost->enc_ctx->codec_type;\n\n            total_size    += ost->data_size;\n            total_packets += ost->packets_written;\n\n            av_log(NULL, AV_LOG_VERBOSE, \"  Output stream #%d:%d (%s): \",\n                   i, j, av_get_media_type_string(type));\n            if (ost->encoding_needed) {\n                av_log(NULL, AV_LOG_VERBOSE, \"%\"PRIu64\" frames encoded\",\n                       ost->frames_encoded);\n                if (type == AVMEDIA_TYPE_AUDIO)\n                    av_log(NULL, AV_LOG_VERBOSE, \" (%\"PRIu64\" samples)\", ost->samples_encoded);\n                av_log(NULL, AV_LOG_VERBOSE, \"; \");\n            }\n\n            av_log(NULL, AV_LOG_VERBOSE, \"%\"PRIu64\" packets muxed (%\"PRIu64\" bytes); \",\n                   ost->packets_written, ost->data_size);\n\n            av_log(NULL, AV_LOG_VERBOSE, \"\\n\");\n        }\n\n        av_log(NULL, AV_LOG_VERBOSE, \"  Total: %\"PRIu64\" packets (%\"PRIu64\" bytes) muxed\\n\",\n               total_packets, total_size);\n    }\n    if(video_size + data_size + audio_size + subtitle_size + extra_size == 0){\n        av_log(NULL, AV_LOG_WARNING, \"Output file is empty, nothing was encoded \");\n        if (pass1_used) {\n            av_log(NULL, AV_LOG_WARNING, \"\\n\");\n        } else {\n            av_log(NULL, AV_LOG_WARNING, \"(check -ss / -t / -frames parameters if used)\\n\");\n        }\n    }\n}\n\nEM_JS(void, send_progress, (double progress, double time), {\n    Module.receiveProgress(progress, time);\n});\n\nstatic void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)\n{\n    AVBPrint buf, buf_script;\n    OutputStream *ost;\n    AVFormatContext *oc;\n    int64_t total_size;\n    AVCodecContext *enc;\n    int vid, i;\n    double bitrate;\n    double speed;\n    int64_t pts = INT64_MIN + 1;\n    static int64_t last_time = -1;\n    static int first_report = 1;\n    static int qp_histogram[52];\n    int hours, mins, secs, us;\n    const char *hours_sign;\n    int ret;\n    float t;\n\n    if (!print_stats && !is_last_report && !progress_avio)\n        return;\n\n    if (!is_last_report) {\n        if (last_time == -1) {\n            last_time = cur_time;\n        }\n        if (((cur_time - last_time) < stats_period && !first_report) ||\n            (first_report && nb_output_dumped < nb_output_files))\n            return;\n        last_time = cur_time;\n    }\n\n    t = (cur_time-timer_start) / 1000000.0;\n\n\n    oc = output_files[0]->ctx;\n\n    total_size = avio_size(oc->pb);\n    if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too\n        total_size = avio_tell(oc->pb);\n\n    vid = 0;\n    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    for (i = 0; i < nb_output_streams; i++) {\n        float q = -1;\n        ost = output_streams[i];\n        enc = ost->enc_ctx;\n        if (!ost->stream_copy)\n            q = ost->quality / (float) FF_QP2LAMBDA;\n\n        if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {\n            av_bprintf(&buf, \"q=%2.1f \", q);\n            av_bprintf(&buf_script, \"stream_%d_%d_q=%.1f\\n\",\n                       ost->file_index, ost->index, q);\n        }\n        if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {\n            float fps;\n            int64_t frame_number = ost->frame_number;\n\n            fps = t > 1 ? frame_number / t : 0;\n            av_bprintf(&buf, \"frame=%5\"PRId64\" fps=%3.*f q=%3.1f \",\n                     frame_number, fps < 9.95, fps, q);\n            av_bprintf(&buf_script, \"frame=%\"PRId64\"\\n\", frame_number);\n            av_bprintf(&buf_script, \"fps=%.2f\\n\", fps);\n            av_bprintf(&buf_script, \"stream_%d_%d_q=%.1f\\n\",\n                       ost->file_index, ost->index, q);\n            if (is_last_report)\n                av_bprintf(&buf, \"L\");\n            if (qp_hist) {\n                int j;\n                int qp = lrintf(q);\n                if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))\n                    qp_histogram[qp]++;\n                for (j = 0; j < 32; j++)\n                    av_bprintf(&buf, \"%X\", av_log2(qp_histogram[j] + 1));\n            }\n\n            if ((enc->flags & AV_CODEC_FLAG_PSNR) && (ost->pict_type != AV_PICTURE_TYPE_NONE || is_last_report)) {\n                int j;\n                double error, error_sum = 0;\n                double scale, scale_sum = 0;\n                double p;\n                char type[3] = { 'Y','U','V' };\n                av_bprintf(&buf, \"PSNR=\");\n                for (j = 0; j < 3; j++) {\n                    if (is_last_report) {\n                        error = enc->error[j];\n                        scale = enc->width * enc->height * 255.0 * 255.0 * frame_number;\n                    } else {\n                        error = ost->error[j];\n                        scale = enc->width * enc->height * 255.0 * 255.0;\n                    }\n                    if (j)\n                        scale /= 4;\n                    error_sum += error;\n                    scale_sum += scale;\n                    p = psnr(error / scale);\n                    av_bprintf(&buf, \"%c:%2.2f \", type[j], p);\n                    av_bprintf(&buf_script, \"stream_%d_%d_psnr_%c=%2.2f\\n\",\n                               ost->file_index, ost->index, type[j] | 32, p);\n                }\n                p = psnr(error_sum / scale_sum);\n                av_bprintf(&buf, \"*:%2.2f \", psnr(error_sum / scale_sum));\n                av_bprintf(&buf_script, \"stream_%d_%d_psnr_all=%2.2f\\n\",\n                           ost->file_index, ost->index, p);\n            }\n            vid = 1;\n        }\n        /* compute min output value */\n        if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE) {\n            pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st),\n                                          ost->st->time_base, AV_TIME_BASE_Q));\n            if (copy_ts) {\n                if (copy_ts_first_pts == AV_NOPTS_VALUE && pts > 1)\n                    copy_ts_first_pts = pts;\n                if (copy_ts_first_pts != AV_NOPTS_VALUE)\n                    pts -= copy_ts_first_pts;\n            }\n        }\n\n        if (is_last_report)\n            nb_frames_drop += ost->last_dropped;\n    }\n\n    /* send_progress here only works when the duration of\n     * input and output file are the same, other cases (ex. trim)\n     * still WIP.\n     *\n     * TODO: support cases like trim.\n     */\n    int64_t duration = -1;\n    int64_t pts_abs = FFABS(pts);\n    /* Use the longest duration among all input files.\n     */\n    for (int i = 0; i < nb_input_files; i++) {\n      int64_t file_duration = input_files[i]->ctx->duration;\n      if (file_duration > duration) {\n        duration = file_duration;\n      }\n    }\n    send_progress((double)pts_abs / (double)duration, (double)pts_abs);\n\n    secs = FFABS(pts) / AV_TIME_BASE;\n    us = FFABS(pts) % AV_TIME_BASE;\n    mins = secs / 60;\n    secs %= 60;\n    hours = mins / 60;\n    mins %= 60;\n    hours_sign = (pts < 0) ? \"-\" : \"\";\n\n    bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1;\n    speed = t != 0.0 ? (double)pts / AV_TIME_BASE / t : -1;\n\n    if (total_size < 0) av_bprintf(&buf, \"size=N/A time=\");\n    else                av_bprintf(&buf, \"size=%8.0fkB time=\", total_size / 1024.0);\n    if (pts == AV_NOPTS_VALUE) {\n        av_bprintf(&buf, \"N/A \");\n    } else {\n        av_bprintf(&buf, \"%s%02d:%02d:%02d.%02d \",\n                   hours_sign, hours, mins, secs, (100 * us) / AV_TIME_BASE);\n    }\n\n    if (bitrate < 0) {\n        av_bprintf(&buf, \"bitrate=N/A\");\n        av_bprintf(&buf_script, \"bitrate=N/A\\n\");\n    }else{\n        av_bprintf(&buf, \"bitrate=%6.1fkbits/s\", bitrate);\n        av_bprintf(&buf_script, \"bitrate=%6.1fkbits/s\\n\", bitrate);\n    }\n\n    if (total_size < 0) av_bprintf(&buf_script, \"total_size=N/A\\n\");\n    else                av_bprintf(&buf_script, \"total_size=%\"PRId64\"\\n\", total_size);\n    if (pts == AV_NOPTS_VALUE) {\n        av_bprintf(&buf_script, \"out_time_us=N/A\\n\");\n        av_bprintf(&buf_script, \"out_time_ms=N/A\\n\");\n        av_bprintf(&buf_script, \"out_time=N/A\\n\");\n    } else {\n        av_bprintf(&buf_script, \"out_time_us=%\"PRId64\"\\n\", pts);\n        av_bprintf(&buf_script, \"out_time_ms=%\"PRId64\"\\n\", pts);\n        av_bprintf(&buf_script, \"out_time=%s%02d:%02d:%02d.%06d\\n\",\n                   hours_sign, hours, mins, secs, us);\n    }\n\n    if (nb_frames_dup || nb_frames_drop)\n        av_bprintf(&buf, \" dup=%\"PRId64\" drop=%\"PRId64, nb_frames_dup, nb_frames_drop);\n    av_bprintf(&buf_script, \"dup_frames=%\"PRId64\"\\n\", nb_frames_dup);\n    av_bprintf(&buf_script, \"drop_frames=%\"PRId64\"\\n\", nb_frames_drop);\n\n    if (speed < 0) {\n        av_bprintf(&buf, \" speed=N/A\");\n        av_bprintf(&buf_script, \"speed=N/A\\n\");\n    } else {\n        av_bprintf(&buf, \" speed=%4.3gx\", speed);\n        av_bprintf(&buf_script, \"speed=%4.3gx\\n\", speed);\n    }\n\n    if (print_stats || is_last_report) {\n        // Always print a new line of message.\n        const char end = '\\n'; //is_last_report ? '\\n' : '\\r';\n        if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {\n            fprintf(stderr, \"%s    %c\", buf.str, end);\n        } else\n            av_log(NULL, AV_LOG_INFO, \"%s    %c\", buf.str, end);\n\n        fflush(stderr);\n    }\n    av_bprint_finalize(&buf, NULL);\n\n    if (progress_avio) {\n        av_bprintf(&buf_script, \"progress=%s\\n\",\n                   is_last_report ? \"end\" : \"continue\");\n        avio_write(progress_avio, buf_script.str,\n                   FFMIN(buf_script.len, buf_script.size - 1));\n        avio_flush(progress_avio);\n        av_bprint_finalize(&buf_script, NULL);\n        if (is_last_report) {\n            if ((ret = avio_closep(&progress_avio)) < 0)\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Error closing progress log, loss of information possible: %s\\n\", av_err2str(ret));\n        }\n    }\n\n    first_report = 0;\n\n    if (is_last_report) {\n      // Make sure the progress is ended with 1.\n      if (pts_abs != duration) send_progress(1, (double)pts_abs);\n      print_final_stats(total_size);\n    }\n}\n\nstatic int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)\n{\n    int ret;\n\n    // We never got any input. Set a fake format, which will\n    // come from libavformat.\n    ifilter->format                 = par->format;\n    ifilter->sample_rate            = par->sample_rate;\n    ifilter->width                  = par->width;\n    ifilter->height                 = par->height;\n    ifilter->sample_aspect_ratio    = par->sample_aspect_ratio;\n    ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout);\n    if (ret < 0)\n        return ret;\n\n    return 0;\n}\n\nstatic void flush_encoders(void)\n{\n    int i, ret;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream   *ost = output_streams[i];\n        AVCodecContext *enc = ost->enc_ctx;\n        OutputFile      *of = output_files[ost->file_index];\n\n        if (!ost->encoding_needed)\n            continue;\n\n        // Try to enable encoding with no input frames.\n        // Maybe we should just let encoding fail instead.\n        if (!ost->initialized) {\n            FilterGraph *fg = ost->filter->graph;\n\n            av_log(NULL, AV_LOG_WARNING,\n                   \"Finishing stream %d:%d without any data written to it.\\n\",\n                   ost->file_index, ost->st->index);\n\n            if (ost->filter && !fg->graph) {\n                int x;\n                for (x = 0; x < fg->nb_inputs; x++) {\n                    InputFilter *ifilter = fg->inputs[x];\n                    if (ifilter->format < 0 &&\n                        ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar) < 0) {\n                        av_log(NULL, AV_LOG_ERROR, \"Error copying paramerets from input stream\\n\");\n                        exit_program(1);\n                    }\n                }\n\n                if (!ifilter_has_all_input_formats(fg))\n                    continue;\n\n                ret = configure_filtergraph(fg);\n                if (ret < 0) {\n                    av_log(NULL, AV_LOG_ERROR, \"Error configuring filter graph\\n\");\n                    exit_program(1);\n                }\n\n                finish_output_stream(ost);\n            }\n\n            init_output_stream_wrapper(ost, NULL, 1);\n        }\n\n        if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)\n            continue;\n\n        ret = encode_frame(of, ost, NULL);\n        if (ret != AVERROR_EOF)\n            exit_program(1);\n    }\n}\n\n/*\n * Check whether a packet from ist should be written into ost at this time\n */\nstatic int check_output_constraints(InputStream *ist, OutputStream *ost)\n{\n    OutputFile *of = output_files[ost->file_index];\n    int ist_index  = input_files[ist->file_index]->ist_index + ist->st->index;\n\n    if (ost->source_index != ist_index)\n        return 0;\n\n    if (ost->finished & MUXER_FINISHED)\n        return 0;\n\n    if (of->start_time != AV_NOPTS_VALUE && ist->pts < of->start_time)\n        return 0;\n\n    return 1;\n}\n\nstatic void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *pkt)\n{\n    OutputFile *of = output_files[ost->file_index];\n    InputFile   *f = input_files [ist->file_index];\n    int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;\n    int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->mux_timebase);\n    AVPacket *opkt = ost->pkt;\n\n    av_packet_unref(opkt);\n    // EOF: flush output bitstream filters.\n    if (!pkt) {\n        output_packet(of, opkt, ost, 1);\n        return;\n    }\n\n    if (!ost->streamcopy_started && !(pkt->flags & AV_PKT_FLAG_KEY) &&\n        !ost->copy_initial_nonkeyframes)\n        return;\n\n    if (!ost->streamcopy_started && !ost->copy_prior_start) {\n        int64_t comp_start = start_time;\n        if (copy_ts && f->start_time != AV_NOPTS_VALUE)\n            comp_start = FFMAX(start_time, f->start_time + f->ts_offset);\n        if (pkt->pts == AV_NOPTS_VALUE ?\n            ist->pts < comp_start :\n            pkt->pts < av_rescale_q(comp_start, AV_TIME_BASE_Q, ist->st->time_base))\n            return;\n    }\n\n    if (of->recording_time != INT64_MAX &&\n        ist->pts >= of->recording_time + start_time) {\n        close_output_stream(ost);\n        return;\n    }\n\n    if (f->recording_time != INT64_MAX) {\n        start_time = 0;\n        if (copy_ts) {\n            start_time += f->start_time != AV_NOPTS_VALUE ? f->start_time : 0;\n            start_time += start_at_zero ? 0 : f->ctx->start_time;\n        }\n        if (ist->pts >= f->recording_time + start_time) {\n            close_output_stream(ost);\n            return;\n        }\n    }\n\n    if (av_packet_ref(opkt, pkt) < 0)\n        exit_program(1);\n\n    if (pkt->pts != AV_NOPTS_VALUE)\n        opkt->pts = av_rescale_q(pkt->pts, ist->st->time_base, ost->mux_timebase) - ost_tb_start_time;\n\n    if (pkt->dts == AV_NOPTS_VALUE) {\n        opkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ost->mux_timebase);\n    } else if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {\n        int duration = av_get_audio_frame_duration(ist->dec_ctx, pkt->size);\n        if(!duration)\n            duration = ist->dec_ctx->frame_size;\n        opkt->dts = av_rescale_delta(ist->st->time_base, pkt->dts,\n                                    (AVRational){1, ist->dec_ctx->sample_rate}, duration,\n                                    &ist->filter_in_rescale_delta_last, ost->mux_timebase);\n        /* dts will be set immediately afterwards to what pts is now */\n        opkt->pts = opkt->dts - ost_tb_start_time;\n    } else\n        opkt->dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->mux_timebase);\n    opkt->dts -= ost_tb_start_time;\n\n    opkt->duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->mux_timebase);\n\n    ost->sync_opts += opkt->duration;\n\n    output_packet(of, opkt, ost, 0);\n\n    ost->streamcopy_started = 1;\n}\n\nint guess_input_channel_layout(InputStream *ist)\n{\n    AVCodecContext *dec = ist->dec_ctx;\n\n    if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {\n        char layout_name[256];\n\n        if (dec->ch_layout.nb_channels > ist->guess_layout_max)\n            return 0;\n        av_channel_layout_default(&dec->ch_layout, dec->ch_layout.nb_channels);\n        if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)\n            return 0;\n        av_channel_layout_describe(&dec->ch_layout, layout_name, sizeof(layout_name));\n        av_log(NULL, AV_LOG_WARNING, \"Guessed Channel Layout for Input Stream \"\n               \"#%d.%d : %s\\n\", ist->file_index, ist->st->index, layout_name);\n    }\n    return 1;\n}\n\nstatic void check_decode_result(InputStream *ist, int *got_output, int ret)\n{\n    if (*got_output || ret<0)\n        decode_error_stat[ret<0] ++;\n\n    if (ret < 0 && exit_on_error)\n        exit_program(1);\n\n    if (*got_output && ist) {\n        if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {\n            av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,\n                   \"%s: corrupt decoded frame in stream %d\\n\", input_files[ist->file_index]->ctx->url, ist->st->index);\n            if (exit_on_error)\n                exit_program(1);\n        }\n    }\n}\n\n// Filters can be configured only if the formats of all inputs are known.\nstatic int ifilter_has_all_input_formats(FilterGraph *fg)\n{\n    int i;\n    for (i = 0; i < fg->nb_inputs; i++) {\n        if (fg->inputs[i]->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||\n                                          fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))\n            return 0;\n    }\n    return 1;\n}\n\nstatic int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)\n{\n    FilterGraph *fg = ifilter->graph;\n    AVFrameSideData *sd;\n    int need_reinit, ret;\n    int buffersrc_flags = AV_BUFFERSRC_FLAG_PUSH;\n\n    if (keep_reference)\n        buffersrc_flags |= AV_BUFFERSRC_FLAG_KEEP_REF;\n\n    /* determine if the parameters for this input changed */\n    need_reinit = ifilter->format != frame->format;\n\n    switch (ifilter->ist->st->codecpar->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        need_reinit |= ifilter->sample_rate    != frame->sample_rate ||\n                       av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout);\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        need_reinit |= ifilter->width  != frame->width ||\n                       ifilter->height != frame->height;\n        break;\n    }\n\n    if (!ifilter->ist->reinit_filters && fg->graph)\n        need_reinit = 0;\n\n    if (!!ifilter->hw_frames_ctx != !!frame->hw_frames_ctx ||\n        (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data))\n        need_reinit = 1;\n\n    if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {\n        if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9))\n            need_reinit = 1;\n    } else if (ifilter->displaymatrix)\n        need_reinit = 1;\n\n    if (need_reinit) {\n        ret = ifilter_parameters_from_frame(ifilter, frame);\n        if (ret < 0)\n            return ret;\n    }\n\n    /* (re)init the graph if possible, otherwise buffer the frame and return */\n    if (need_reinit || !fg->graph) {\n        if (!ifilter_has_all_input_formats(fg)) {\n            AVFrame *tmp = av_frame_clone(frame);\n            if (!tmp)\n                return AVERROR(ENOMEM);\n\n            ret = av_fifo_write(ifilter->frame_queue, &tmp, 1);\n            if (ret < 0)\n                av_frame_free(&tmp);\n\n            return ret;\n        }\n\n        ret = reap_filters(1);\n        if (ret < 0 && ret != AVERROR_EOF) {\n            av_log(NULL, AV_LOG_ERROR, \"Error while filtering: %s\\n\", av_err2str(ret));\n            return ret;\n        }\n\n        ret = configure_filtergraph(fg);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error reinitializing filters!\\n\");\n            return ret;\n        }\n    }\n\n    ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, buffersrc_flags);\n    if (ret < 0) {\n        if (ret != AVERROR_EOF)\n            av_log(NULL, AV_LOG_ERROR, \"Error while filtering: %s\\n\", av_err2str(ret));\n        return ret;\n    }\n\n    return 0;\n}\n\nstatic int ifilter_send_eof(InputFilter *ifilter, int64_t pts)\n{\n    int ret;\n\n    ifilter->eof = 1;\n\n    if (ifilter->filter) {\n        ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH);\n        if (ret < 0)\n            return ret;\n    } else {\n        // the filtergraph was never configured\n        if (ifilter->format < 0) {\n            ret = ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar);\n            if (ret < 0)\n                return ret;\n        }\n        if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {\n            av_log(NULL, AV_LOG_ERROR, \"Cannot determine format of input stream %d:%d after EOF\\n\", ifilter->ist->file_index, ifilter->ist->st->index);\n            return AVERROR_INVALIDDATA;\n        }\n    }\n\n    return 0;\n}\n\n// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.\n// There is the following difference: if you got a frame, you must call\n// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0\n// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)\nstatic int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)\n{\n    int ret;\n\n    *got_frame = 0;\n\n    if (pkt) {\n        ret = avcodec_send_packet(avctx, pkt);\n        // In particular, we don't expect AVERROR(EAGAIN), because we read all\n        // decoded frames with avcodec_receive_frame() until done.\n        if (ret < 0 && ret != AVERROR_EOF)\n            return ret;\n    }\n\n    ret = avcodec_receive_frame(avctx, frame);\n    if (ret < 0 && ret != AVERROR(EAGAIN))\n        return ret;\n    if (ret >= 0)\n        *got_frame = 1;\n\n    return 0;\n}\n\nstatic int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)\n{\n    int i, ret;\n\n    av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */\n    for (i = 0; i < ist->nb_filters; i++) {\n        ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1);\n        if (ret == AVERROR_EOF)\n            ret = 0; /* ignore */\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Failed to inject frame into filter network: %s\\n\", av_err2str(ret));\n            break;\n        }\n    }\n    return ret;\n}\n\nstatic int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output,\n                        int *decode_failed)\n{\n    AVFrame *decoded_frame = ist->decoded_frame;\n    AVCodecContext *avctx = ist->dec_ctx;\n    int ret, err = 0;\n    AVRational decoded_frame_tb;\n\n    update_benchmark(NULL);\n    ret = decode(avctx, decoded_frame, got_output, pkt);\n    update_benchmark(\"decode_audio %d.%d\", ist->file_index, ist->st->index);\n    if (ret < 0)\n        *decode_failed = 1;\n\n    if (ret >= 0 && avctx->sample_rate <= 0) {\n        av_log(avctx, AV_LOG_ERROR, \"Sample rate %d invalid\\n\", avctx->sample_rate);\n        ret = AVERROR_INVALIDDATA;\n    }\n\n    if (ret != AVERROR_EOF)\n        check_decode_result(ist, got_output, ret);\n\n    if (!*got_output || ret < 0)\n        return ret;\n\n    ist->samples_decoded += decoded_frame->nb_samples;\n    ist->frames_decoded++;\n\n    /* increment next_dts to use for the case where the input stream does not\n       have timestamps or there are multiple frames in the packet */\n    ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /\n                     avctx->sample_rate;\n    ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /\n                     avctx->sample_rate;\n\n    if (decoded_frame->pts != AV_NOPTS_VALUE) {\n        decoded_frame_tb   = ist->st->time_base;\n    } else if (pkt && pkt->pts != AV_NOPTS_VALUE) {\n        decoded_frame->pts = pkt->pts;\n        decoded_frame_tb   = ist->st->time_base;\n    }else {\n        decoded_frame->pts = ist->dts;\n        decoded_frame_tb   = AV_TIME_BASE_Q;\n    }\n    if (pkt && pkt->duration && ist->prev_pkt_pts != AV_NOPTS_VALUE &&\n        pkt->pts != AV_NOPTS_VALUE && pkt->pts - ist->prev_pkt_pts > pkt->duration)\n        ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;\n    if (pkt)\n        ist->prev_pkt_pts = pkt->pts;\n    if (decoded_frame->pts != AV_NOPTS_VALUE)\n        decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,\n                                              (AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,\n                                              (AVRational){1, avctx->sample_rate});\n    ist->nb_samples = decoded_frame->nb_samples;\n    err = send_frame_to_filters(ist, decoded_frame);\n\n    av_frame_unref(decoded_frame);\n    return err < 0 ? err : ret;\n}\n\nstatic int decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *duration_pts, int eof,\n                        int *decode_failed)\n{\n    AVFrame *decoded_frame = ist->decoded_frame;\n    int i, ret = 0, err = 0;\n    int64_t best_effort_timestamp;\n    int64_t dts = AV_NOPTS_VALUE;\n\n    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some\n    // reason. This seems like a semi-critical bug. Don't trigger EOF, and\n    // skip the packet.\n    if (!eof && pkt && pkt->size == 0)\n        return 0;\n\n    if (ist->dts != AV_NOPTS_VALUE)\n        dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);\n    if (pkt) {\n        pkt->dts = dts; // ffmpeg.c probably shouldn't do this\n    }\n\n    // The old code used to set dts on the drain packet, which does not work\n    // with the new API anymore.\n    if (eof) {\n        void *new = av_realloc_array(ist->dts_buffer, ist->nb_dts_buffer + 1, sizeof(ist->dts_buffer[0]));\n        if (!new)\n            return AVERROR(ENOMEM);\n        ist->dts_buffer = new;\n        ist->dts_buffer[ist->nb_dts_buffer++] = dts;\n    }\n\n    update_benchmark(NULL);\n    ret = decode(ist->dec_ctx, decoded_frame, got_output, pkt);\n    update_benchmark(\"decode_video %d.%d\", ist->file_index, ist->st->index);\n    if (ret < 0)\n        *decode_failed = 1;\n\n    // The following line may be required in some cases where there is no parser\n    // or the parser does not has_b_frames correctly\n    if (ist->st->codecpar->video_delay < ist->dec_ctx->has_b_frames) {\n        if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) {\n            ist->st->codecpar->video_delay = ist->dec_ctx->has_b_frames;\n        } else\n            av_log(ist->dec_ctx, AV_LOG_WARNING,\n                   \"video_delay is larger in decoder than demuxer %d > %d.\\n\"\n                   \"If you want to help, upload a sample \"\n                   \"of this file to https://streams.videolan.org/upload/ \"\n                   \"and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\\n\",\n                   ist->dec_ctx->has_b_frames,\n                   ist->st->codecpar->video_delay);\n    }\n\n    if (ret != AVERROR_EOF)\n        check_decode_result(ist, got_output, ret);\n\n    if (*got_output && ret >= 0) {\n        if (ist->dec_ctx->width  != decoded_frame->width ||\n            ist->dec_ctx->height != decoded_frame->height ||\n            ist->dec_ctx->pix_fmt != decoded_frame->format) {\n            av_log(NULL, AV_LOG_DEBUG, \"Frame parameters mismatch context %d,%d,%d != %d,%d,%d\\n\",\n                decoded_frame->width,\n                decoded_frame->height,\n                decoded_frame->format,\n                ist->dec_ctx->width,\n                ist->dec_ctx->height,\n                ist->dec_ctx->pix_fmt);\n        }\n    }\n\n    if (!*got_output || ret < 0)\n        return ret;\n\n    if(ist->top_field_first>=0)\n        decoded_frame->top_field_first = ist->top_field_first;\n\n    ist->frames_decoded++;\n\n    if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {\n        err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame);\n        if (err < 0)\n            goto fail;\n    }\n    ist->hwaccel_retrieved_pix_fmt = decoded_frame->format;\n\n    best_effort_timestamp= decoded_frame->best_effort_timestamp;\n    *duration_pts = decoded_frame->pkt_duration;\n\n    if (ist->framerate.num)\n        best_effort_timestamp = ist->cfr_next_pts++;\n\n    if (eof && best_effort_timestamp == AV_NOPTS_VALUE && ist->nb_dts_buffer > 0) {\n        best_effort_timestamp = ist->dts_buffer[0];\n\n        for (i = 0; i < ist->nb_dts_buffer - 1; i++)\n            ist->dts_buffer[i] = ist->dts_buffer[i + 1];\n        ist->nb_dts_buffer--;\n    }\n\n    if(best_effort_timestamp != AV_NOPTS_VALUE) {\n        int64_t ts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);\n\n        if (ts != AV_NOPTS_VALUE)\n            ist->next_pts = ist->pts = ts;\n    }\n\n    if (debug_ts) {\n        av_log(NULL, AV_LOG_INFO, \"decoder -> ist_index:%d type:video \"\n               \"frame_pts:%s frame_pts_time:%s best_effort_ts:%\"PRId64\" best_effort_ts_time:%s keyframe:%d frame_type:%d time_base:%d/%d\\n\",\n               ist->st->index, av_ts2str(decoded_frame->pts),\n               av_ts2timestr(decoded_frame->pts, &ist->st->time_base),\n               best_effort_timestamp,\n               av_ts2timestr(best_effort_timestamp, &ist->st->time_base),\n               decoded_frame->key_frame, decoded_frame->pict_type,\n               ist->st->time_base.num, ist->st->time_base.den);\n    }\n\n    if (ist->st->sample_aspect_ratio.num)\n        decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;\n\n    err = send_frame_to_filters(ist, decoded_frame);\n\nfail:\n    av_frame_unref(decoded_frame);\n    return err < 0 ? err : ret;\n}\n\nstatic int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output,\n                               int *decode_failed)\n{\n    AVSubtitle subtitle;\n    int free_sub = 1;\n    int i, ret = avcodec_decode_subtitle2(ist->dec_ctx,\n                                          &subtitle, got_output, pkt);\n\n    check_decode_result(NULL, got_output, ret);\n\n    if (ret < 0 || !*got_output) {\n        *decode_failed = 1;\n        if (!pkt->size)\n            sub2video_flush(ist);\n        return ret;\n    }\n\n    if (ist->fix_sub_duration) {\n        int end = 1;\n        if (ist->prev_sub.got_output) {\n            end = av_rescale(subtitle.pts - ist->prev_sub.subtitle.pts,\n                             1000, AV_TIME_BASE);\n            if (end < ist->prev_sub.subtitle.end_display_time) {\n                av_log(ist->dec_ctx, AV_LOG_DEBUG,\n                       \"Subtitle duration reduced from %\"PRId32\" to %d%s\\n\",\n                       ist->prev_sub.subtitle.end_display_time, end,\n                       end <= 0 ? \", dropping it\" : \"\");\n                ist->prev_sub.subtitle.end_display_time = end;\n            }\n        }\n        FFSWAP(int,        *got_output, ist->prev_sub.got_output);\n        FFSWAP(int,        ret,         ist->prev_sub.ret);\n        FFSWAP(AVSubtitle, subtitle,    ist->prev_sub.subtitle);\n        if (end <= 0)\n            goto out;\n    }\n\n    if (!*got_output)\n        return ret;\n\n    if (ist->sub2video.frame) {\n        sub2video_update(ist, INT64_MIN, &subtitle);\n    } else if (ist->nb_filters) {\n        if (!ist->sub2video.sub_queue)\n            ist->sub2video.sub_queue = av_fifo_alloc2(8, sizeof(AVSubtitle), AV_FIFO_FLAG_AUTO_GROW);\n        if (!ist->sub2video.sub_queue)\n            exit_program(1);\n\n        ret = av_fifo_write(ist->sub2video.sub_queue, &subtitle, 1);\n        if (ret < 0)\n            exit_program(1);\n        free_sub = 0;\n    }\n\n    if (!subtitle.num_rects)\n        goto out;\n\n    ist->frames_decoded++;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n\n        if (!check_output_constraints(ist, ost) || !ost->encoding_needed\n            || ost->enc->type != AVMEDIA_TYPE_SUBTITLE)\n            continue;\n\n        do_subtitle_out(output_files[ost->file_index], ost, &subtitle);\n    }\n\nout:\n    if (free_sub)\n        avsubtitle_free(&subtitle);\n    return ret;\n}\n\nstatic int send_filter_eof(InputStream *ist)\n{\n    int i, ret;\n    /* TODO keep pts also in stream time base to avoid converting back */\n    int64_t pts = av_rescale_q_rnd(ist->pts, AV_TIME_BASE_Q, ist->st->time_base,\n                                   AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);\n\n    for (i = 0; i < ist->nb_filters; i++) {\n        ret = ifilter_send_eof(ist->filters[i], pts);\n        if (ret < 0)\n            return ret;\n    }\n    return 0;\n}\n\n/* pkt = NULL means EOF (needed to flush decoder buffers) */\nstatic int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)\n{\n    int ret = 0, i;\n    int repeating = 0;\n    int eof_reached = 0;\n\n    AVPacket *avpkt = ist->pkt;\n\n    if (!ist->saw_first_ts) {\n        ist->first_dts =\n        ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;\n        ist->pts = 0;\n        if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {\n            ist->first_dts =\n            ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);\n            ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong\n        }\n        ist->saw_first_ts = 1;\n    }\n\n    if (ist->next_dts == AV_NOPTS_VALUE)\n        ist->next_dts = ist->dts;\n    if (ist->next_pts == AV_NOPTS_VALUE)\n        ist->next_pts = ist->pts;\n\n    if (pkt) {\n        av_packet_unref(avpkt);\n        ret = av_packet_ref(avpkt, pkt);\n        if (ret < 0)\n            return ret;\n    }\n\n    if (pkt && pkt->dts != AV_NOPTS_VALUE) {\n        ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);\n        if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)\n            ist->next_pts = ist->pts = ist->dts;\n    }\n\n    // while we have more to decode or while the decoder did output something on EOF\n    while (ist->decoding_needed) {\n        int64_t duration_dts = 0;\n        int64_t duration_pts = 0;\n        int got_output = 0;\n        int decode_failed = 0;\n\n        ist->pts = ist->next_pts;\n        ist->dts = ist->next_dts;\n\n        switch (ist->dec_ctx->codec_type) {\n        case AVMEDIA_TYPE_AUDIO:\n            ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,\n                                   &decode_failed);\n            av_packet_unref(avpkt);\n            break;\n        case AVMEDIA_TYPE_VIDEO:\n            ret = decode_video    (ist, repeating ? NULL : avpkt, &got_output, &duration_pts, !pkt,\n                                   &decode_failed);\n            if (!repeating || !pkt || got_output) {\n                if (pkt && pkt->duration) {\n                    duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);\n                } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {\n                    int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame;\n                    duration_dts = ((int64_t)AV_TIME_BASE *\n                                    ist->dec_ctx->framerate.den * ticks) /\n                                    ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;\n                }\n\n                if(ist->dts != AV_NOPTS_VALUE && duration_dts) {\n                    ist->next_dts += duration_dts;\n                }else\n                    ist->next_dts = AV_NOPTS_VALUE;\n            }\n\n            if (got_output) {\n                if (duration_pts > 0) {\n                    ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q);\n                } else {\n                    ist->next_pts += duration_dts;\n                }\n            }\n            av_packet_unref(avpkt);\n            break;\n        case AVMEDIA_TYPE_SUBTITLE:\n            if (repeating)\n                break;\n            ret = transcode_subtitles(ist, avpkt, &got_output, &decode_failed);\n            if (!pkt && ret >= 0)\n                ret = AVERROR_EOF;\n            av_packet_unref(avpkt);\n            break;\n        default:\n            return -1;\n        }\n\n        if (ret == AVERROR_EOF) {\n            eof_reached = 1;\n            break;\n        }\n\n        if (ret < 0) {\n            if (decode_failed) {\n                av_log(NULL, AV_LOG_ERROR, \"Error while decoding stream #%d:%d: %s\\n\",\n                       ist->file_index, ist->st->index, av_err2str(ret));\n            } else {\n                av_log(NULL, AV_LOG_FATAL, \"Error while processing the decoded \"\n                       \"data for stream #%d:%d\\n\", ist->file_index, ist->st->index);\n            }\n            if (!decode_failed || exit_on_error)\n                exit_program(1);\n            break;\n        }\n\n        if (got_output)\n            ist->got_output = 1;\n\n        if (!got_output)\n            break;\n\n        // During draining, we might get multiple output frames in this loop.\n        // ffmpeg.c does not drain the filter chain on configuration changes,\n        // which means if we send multiple frames at once to the filters, and\n        // one of those frames changes configuration, the buffered frames will\n        // be lost. This can upset certain FATE tests.\n        // Decode only 1 frame per call on EOF to appease these FATE tests.\n        // The ideal solution would be to rewrite decoding to use the new\n        // decoding API in a better way.\n        if (!pkt)\n            break;\n\n        repeating = 1;\n    }\n\n    /* after flushing, send an EOF on all the filter inputs attached to the stream */\n    /* except when looping we need to flush but not to send an EOF */\n    if (!pkt && ist->decoding_needed && eof_reached && !no_eof) {\n        int ret = send_filter_eof(ist);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Error marking filters as finished\\n\");\n            exit_program(1);\n        }\n    }\n\n    /* handle stream copy */\n    if (!ist->decoding_needed && pkt) {\n        ist->dts = ist->next_dts;\n        switch (ist->dec_ctx->codec_type) {\n        case AVMEDIA_TYPE_AUDIO:\n            av_assert1(pkt->duration >= 0);\n            if (ist->dec_ctx->sample_rate) {\n                ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /\n                                  ist->dec_ctx->sample_rate;\n            } else {\n                ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);\n            }\n            break;\n        case AVMEDIA_TYPE_VIDEO:\n            if (ist->framerate.num) {\n                // TODO: Remove work-around for c99-to-c89 issue 7\n                AVRational time_base_q = AV_TIME_BASE_Q;\n                int64_t next_dts = av_rescale_q(ist->next_dts, time_base_q, av_inv_q(ist->framerate));\n                ist->next_dts = av_rescale_q(next_dts + 1, av_inv_q(ist->framerate), time_base_q);\n            } else if (pkt->duration) {\n                ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);\n            } else if(ist->dec_ctx->framerate.num != 0) {\n                int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;\n                ist->next_dts += ((int64_t)AV_TIME_BASE *\n                                  ist->dec_ctx->framerate.den * ticks) /\n                                  ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;\n            }\n            break;\n        }\n        ist->pts = ist->dts;\n        ist->next_pts = ist->next_dts;\n    } else if (!ist->decoding_needed)\n        eof_reached = 1;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n\n        if (!check_output_constraints(ist, ost) || ost->encoding_needed)\n            continue;\n\n        do_streamcopy(ist, ost, pkt);\n    }\n\n    return !eof_reached;\n}\n\nstatic enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)\n{\n    InputStream *ist = s->opaque;\n    const enum AVPixelFormat *p;\n    int ret;\n\n    for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {\n        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);\n        const AVCodecHWConfig  *config = NULL;\n        int i;\n\n        if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))\n            break;\n\n        if (ist->hwaccel_id == HWACCEL_GENERIC ||\n            ist->hwaccel_id == HWACCEL_AUTO) {\n            for (i = 0;; i++) {\n                config = avcodec_get_hw_config(s->codec, i);\n                if (!config)\n                    break;\n                if (!(config->methods &\n                      AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))\n                    continue;\n                if (config->pix_fmt == *p)\n                    break;\n            }\n        }\n        if (config && config->device_type == ist->hwaccel_device_type) {\n            ret = hwaccel_decode_init(s);\n            if (ret < 0) {\n                if (ist->hwaccel_id == HWACCEL_GENERIC) {\n                    av_log(NULL, AV_LOG_FATAL,\n                           \"%s hwaccel requested for input stream #%d:%d, \"\n                           \"but cannot be initialized.\\n\",\n                           av_hwdevice_get_type_name(config->device_type),\n                           ist->file_index, ist->st->index);\n                    return AV_PIX_FMT_NONE;\n                }\n                continue;\n            }\n\n            ist->hwaccel_pix_fmt = *p;\n            break;\n        }\n    }\n\n    return *p;\n}\n\nstatic int init_input_stream(int ist_index, char *error, int error_len)\n{\n    int ret;\n    InputStream *ist = input_streams[ist_index];\n\n    if (ist->decoding_needed) {\n        const AVCodec *codec = ist->dec;\n        if (!codec) {\n            snprintf(error, error_len, \"Decoder (codec %s) not found for input stream #%d:%d\",\n                    avcodec_get_name(ist->dec_ctx->codec_id), ist->file_index, ist->st->index);\n            return AVERROR(EINVAL);\n        }\n\n        ist->dec_ctx->opaque                = ist;\n        ist->dec_ctx->get_format            = get_format;\n#if LIBAVCODEC_VERSION_MAJOR < 60\n        AV_NOWARN_DEPRECATED({\n        ist->dec_ctx->thread_safe_callbacks = 1;\n        })\n#endif\n\n        if (ist->dec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE &&\n           (ist->decoding_needed & DECODING_FOR_OST)) {\n            av_dict_set(&ist->decoder_opts, \"compute_edt\", \"1\", AV_DICT_DONT_OVERWRITE);\n            if (ist->decoding_needed & DECODING_FOR_FILTER)\n                av_log(NULL, AV_LOG_WARNING, \"Warning using DVB subtitles for filtering and output at the same time is not fully supported, also see -compute_edt [0|1]\\n\");\n        }\n\n        /* Useful for subtitles retiming by lavf (FIXME), skipping samples in\n         * audio, and video decoders such as cuvid or mediacodec */\n        ist->dec_ctx->pkt_timebase = ist->st->time_base;\n\n        if (!av_dict_get(ist->decoder_opts, \"threads\", NULL, 0))\n            av_dict_set(&ist->decoder_opts, \"threads\", \"auto\", 0);\n        /* Attached pics are sparse, therefore we would not want to delay their decoding till EOF. */\n        if (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)\n            av_dict_set(&ist->decoder_opts, \"threads\", \"1\", 0);\n\n        ret = hw_device_setup_for_decode(ist);\n        if (ret < 0) {\n            snprintf(error, error_len, \"Device setup failed for \"\n                     \"decoder on input stream #%d:%d : %s\",\n                     ist->file_index, ist->st->index, av_err2str(ret));\n            return ret;\n        }\n\n        if ((ret = avcodec_open2(ist->dec_ctx, codec, &ist->decoder_opts)) < 0) {\n            if (ret == AVERROR_EXPERIMENTAL)\n                abort_codec_experimental(codec, 0);\n\n            snprintf(error, error_len,\n                     \"Error while opening decoder for input stream \"\n                     \"#%d:%d : %s\",\n                     ist->file_index, ist->st->index, av_err2str(ret));\n            return ret;\n        }\n        assert_avoptions(ist->decoder_opts);\n    }\n\n    ist->next_pts = AV_NOPTS_VALUE;\n    ist->next_dts = AV_NOPTS_VALUE;\n\n    return 0;\n}\n\nstatic InputStream *get_input_stream(OutputStream *ost)\n{\n    if (ost->source_index >= 0)\n        return input_streams[ost->source_index];\n    return NULL;\n}\n\nstatic int compare_int64(const void *a, const void *b)\n{\n    return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);\n}\n\nstatic int init_output_bsfs(OutputStream *ost)\n{\n    AVBSFContext *ctx = ost->bsf_ctx;\n    int ret;\n\n    if (!ctx)\n        return 0;\n\n    ret = avcodec_parameters_copy(ctx->par_in, ost->st->codecpar);\n    if (ret < 0)\n        return ret;\n\n    ctx->time_base_in = ost->st->time_base;\n\n    ret = av_bsf_init(ctx);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Error initializing bitstream filter: %s\\n\",\n               ctx->filter->name);\n        return ret;\n    }\n\n    ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out);\n    if (ret < 0)\n        return ret;\n    ost->st->time_base = ctx->time_base_out;\n\n    return 0;\n}\n\nstatic int init_output_stream_streamcopy(OutputStream *ost)\n{\n    OutputFile *of = output_files[ost->file_index];\n    InputStream *ist = get_input_stream(ost);\n    AVCodecParameters *par_dst = ost->st->codecpar;\n    AVCodecParameters *par_src = ost->ref_par;\n    AVRational sar;\n    int i, ret;\n    uint32_t codec_tag = par_dst->codec_tag;\n\n    av_assert0(ist && !ost->filter);\n\n    ret = avcodec_parameters_to_context(ost->enc_ctx, ist->st->codecpar);\n    if (ret >= 0)\n        ret = av_opt_set_dict(ost->enc_ctx, &ost->encoder_opts);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL,\n               \"Error setting up codec context options.\\n\");\n        return ret;\n    }\n\n    ret = avcodec_parameters_from_context(par_src, ost->enc_ctx);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL,\n               \"Error getting reference codec parameters.\\n\");\n        return ret;\n    }\n\n    if (!codec_tag) {\n        unsigned int codec_tag_tmp;\n        if (!of->format->codec_tag ||\n            av_codec_get_id (of->format->codec_tag, par_src->codec_tag) == par_src->codec_id ||\n            !av_codec_get_tag2(of->format->codec_tag, par_src->codec_id, &codec_tag_tmp))\n            codec_tag = par_src->codec_tag;\n    }\n\n    ret = avcodec_parameters_copy(par_dst, par_src);\n    if (ret < 0)\n        return ret;\n\n    par_dst->codec_tag = codec_tag;\n\n    if (!ost->frame_rate.num)\n        ost->frame_rate = ist->framerate;\n\n    if (ost->frame_rate.num)\n        ost->st->avg_frame_rate = ost->frame_rate;\n    else\n        ost->st->avg_frame_rate = ist->st->avg_frame_rate;\n\n    ret = avformat_transfer_internal_stream_timing_info(of->format, ost->st, ist->st, copy_tb);\n    if (ret < 0)\n        return ret;\n\n    // copy timebase while removing common factors\n    if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) {\n        if (ost->frame_rate.num)\n            ost->st->time_base = av_inv_q(ost->frame_rate);\n        else\n            ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1});\n    }\n\n    // copy estimated duration as a hint to the muxer\n    if (ost->st->duration <= 0 && ist->st->duration > 0)\n        ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);\n\n    if (ist->st->nb_side_data) {\n        for (i = 0; i < ist->st->nb_side_data; i++) {\n            const AVPacketSideData *sd_src = &ist->st->side_data[i];\n            uint8_t *dst_data;\n\n            dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);\n            if (!dst_data)\n                return AVERROR(ENOMEM);\n            memcpy(dst_data, sd_src->data, sd_src->size);\n        }\n    }\n\n    if (ost->rotate_overridden) {\n        uint8_t *sd = av_stream_new_side_data(ost->st, AV_PKT_DATA_DISPLAYMATRIX,\n                                              sizeof(int32_t) * 9);\n        if (sd)\n            av_display_rotation_set((int32_t *)sd, -ost->rotate_override_value);\n    }\n\n    switch (par_dst->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        if (audio_volume != 256) {\n            av_log(NULL, AV_LOG_FATAL, \"-acodec copy and -vol are incompatible (frames are not decoded)\\n\");\n            exit_program(1);\n        }\n        if((par_dst->block_align == 1 || par_dst->block_align == 1152 || par_dst->block_align == 576) && par_dst->codec_id == AV_CODEC_ID_MP3)\n            par_dst->block_align= 0;\n        if(par_dst->codec_id == AV_CODEC_ID_AC3)\n            par_dst->block_align= 0;\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option\n            sar =\n                av_mul_q(ost->frame_aspect_ratio,\n                         (AVRational){ par_dst->height, par_dst->width });\n            av_log(NULL, AV_LOG_WARNING, \"Overriding aspect ratio \"\n                   \"with stream copy may produce invalid files\\n\");\n            }\n        else if (ist->st->sample_aspect_ratio.num)\n            sar = ist->st->sample_aspect_ratio;\n        else\n            sar = par_src->sample_aspect_ratio;\n        ost->st->sample_aspect_ratio = par_dst->sample_aspect_ratio = sar;\n        ost->st->avg_frame_rate = ist->st->avg_frame_rate;\n        ost->st->r_frame_rate = ist->st->r_frame_rate;\n        break;\n    }\n\n    ost->mux_timebase = ist->st->time_base;\n\n    return 0;\n}\n\nstatic void set_encoder_id(OutputFile *of, OutputStream *ost)\n{\n    const AVDictionaryEntry *e;\n\n    uint8_t *encoder_string;\n    int encoder_string_len;\n    int format_flags = 0;\n    int codec_flags = ost->enc_ctx->flags;\n\n    if (av_dict_get(ost->st->metadata, \"encoder\",  NULL, 0))\n        return;\n\n    e = av_dict_get(of->opts, \"fflags\", NULL, 0);\n    if (e) {\n        const AVOption *o = av_opt_find(of->ctx, \"fflags\", NULL, 0, 0);\n        if (!o)\n            return;\n        av_opt_eval_flags(of->ctx, o, e->value, &format_flags);\n    }\n    e = av_dict_get(ost->encoder_opts, \"flags\", NULL, 0);\n    if (e) {\n        const AVOption *o = av_opt_find(ost->enc_ctx, \"flags\", NULL, 0, 0);\n        if (!o)\n            return;\n        av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags);\n    }\n\n    encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;\n    encoder_string     = av_mallocz(encoder_string_len);\n    if (!encoder_string)\n        exit_program(1);\n\n    if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & AV_CODEC_FLAG_BITEXACT))\n        av_strlcpy(encoder_string, LIBAVCODEC_IDENT \" \", encoder_string_len);\n    else\n        av_strlcpy(encoder_string, \"Lavc \", encoder_string_len);\n    av_strlcat(encoder_string, ost->enc->name, encoder_string_len);\n    av_dict_set(&ost->st->metadata, \"encoder\",  encoder_string,\n                AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);\n}\n\nstatic void parse_forced_key_frames(char *kf, OutputStream *ost,\n                                    AVCodecContext *avctx)\n{\n    char *p;\n    int n = 1, i, size, index = 0;\n    int64_t t, *pts;\n\n    for (p = kf; *p; p++)\n        if (*p == ',')\n            n++;\n    size = n;\n    pts = av_malloc_array(size, sizeof(*pts));\n    if (!pts) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not allocate forced key frames array.\\n\");\n        exit_program(1);\n    }\n\n    p = kf;\n    for (i = 0; i < n; i++) {\n        char *next = strchr(p, ',');\n\n        if (next)\n            *next++ = 0;\n\n        if (!memcmp(p, \"chapters\", 8)) {\n\n            AVFormatContext *avf = output_files[ost->file_index]->ctx;\n            int j;\n\n            if (avf->nb_chapters > INT_MAX - size ||\n                !(pts = av_realloc_f(pts, size += avf->nb_chapters - 1,\n                                     sizeof(*pts)))) {\n                av_log(NULL, AV_LOG_FATAL,\n                       \"Could not allocate forced key frames array.\\n\");\n                exit_program(1);\n            }\n            t = p[8] ? parse_time_or_die(\"force_key_frames\", p + 8, 1) : 0;\n            t = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);\n\n            for (j = 0; j < avf->nb_chapters; j++) {\n                AVChapter *c = avf->chapters[j];\n                av_assert1(index < size);\n                pts[index++] = av_rescale_q(c->start, c->time_base,\n                                            avctx->time_base) + t;\n            }\n\n        } else {\n\n            t = parse_time_or_die(\"force_key_frames\", p, 1);\n            av_assert1(index < size);\n            pts[index++] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);\n\n        }\n\n        p = next;\n    }\n\n    av_assert0(index == size);\n    qsort(pts, size, sizeof(*pts), compare_int64);\n    ost->forced_kf_count = size;\n    ost->forced_kf_pts   = pts;\n}\n\nstatic void init_encoder_time_base(OutputStream *ost, AVRational default_time_base)\n{\n    InputStream *ist = get_input_stream(ost);\n    AVCodecContext *enc_ctx = ost->enc_ctx;\n    AVFormatContext *oc;\n\n    if (ost->enc_timebase.num > 0) {\n        enc_ctx->time_base = ost->enc_timebase;\n        return;\n    }\n\n    if (ost->enc_timebase.num < 0) {\n        if (ist) {\n            enc_ctx->time_base = ist->st->time_base;\n            return;\n        }\n\n        oc = output_files[ost->file_index]->ctx;\n        av_log(oc, AV_LOG_WARNING, \"Input stream data not available, using default time base\\n\");\n    }\n\n    enc_ctx->time_base = default_time_base;\n}\n\nstatic int init_output_stream_encode(OutputStream *ost, AVFrame *frame)\n{\n    InputStream *ist = get_input_stream(ost);\n    AVCodecContext *enc_ctx = ost->enc_ctx;\n    AVCodecContext *dec_ctx = NULL;\n    OutputFile      *of = output_files[ost->file_index];\n    AVFormatContext *oc = of->ctx;\n    int ret;\n\n    set_encoder_id(output_files[ost->file_index], ost);\n\n    if (ist) {\n        dec_ctx = ist->dec_ctx;\n    }\n\n    if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {\n        if (!ost->frame_rate.num)\n            ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);\n        if (ist && !ost->frame_rate.num && !ost->max_frame_rate.num) {\n            ost->frame_rate = (AVRational){25, 1};\n            av_log(NULL, AV_LOG_WARNING,\n                   \"No information \"\n                   \"about the input framerate is available. Falling \"\n                   \"back to a default value of 25fps for output stream #%d:%d. Use the -r option \"\n                   \"if you want a different framerate.\\n\",\n                   ost->file_index, ost->index);\n        }\n\n        if (ost->max_frame_rate.num &&\n            (av_q2d(ost->frame_rate) > av_q2d(ost->max_frame_rate) ||\n            !ost->frame_rate.den))\n            ost->frame_rate = ost->max_frame_rate;\n\n        if (ost->enc->supported_framerates && !ost->force_fps) {\n            int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);\n            ost->frame_rate = ost->enc->supported_framerates[idx];\n        }\n        // reduce frame rate for mpeg4 to be within the spec limits\n        if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {\n            av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,\n                      ost->frame_rate.num, ost->frame_rate.den, 65535);\n        }\n    }\n\n    switch (enc_ctx->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        enc_ctx->sample_fmt     = av_buffersink_get_format(ost->filter->filter);\n        enc_ctx->sample_rate    = av_buffersink_get_sample_rate(ost->filter->filter);\n        ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout);\n        if (ret < 0)\n            return ret;\n\n        if (ost->bits_per_raw_sample)\n            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;\n        else if (dec_ctx && ost->filter->graph->is_meta)\n            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,\n                                                 av_get_bytes_per_sample(enc_ctx->sample_fmt) << 3);\n\n        init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate));\n        break;\n\n    case AVMEDIA_TYPE_VIDEO:\n        init_encoder_time_base(ost, av_inv_q(ost->frame_rate));\n\n        if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))\n            enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter);\n        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH\n           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||\n               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){\n            av_log(oc, AV_LOG_WARNING, \"Frame rate very high for a muxer not efficiently supporting it.\\n\"\n                                       \"Please consider specifying a lower framerate, a different muxer or \"\n                                       \"setting vsync/fps_mode to vfr\\n\");\n        }\n\n        enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);\n        enc_ctx->height = av_buffersink_get_h(ost->filter->filter);\n        enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =\n            ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option\n            av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :\n            av_buffersink_get_sample_aspect_ratio(ost->filter->filter);\n\n        enc_ctx->pix_fmt = av_buffersink_get_format(ost->filter->filter);\n\n        if (ost->bits_per_raw_sample)\n            enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample;\n        else if (dec_ctx && ost->filter->graph->is_meta)\n            enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,\n                                                 av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);\n\n        if (frame) {\n            enc_ctx->color_range            = frame->color_range;\n            enc_ctx->color_primaries        = frame->color_primaries;\n            enc_ctx->color_trc              = frame->color_trc;\n            enc_ctx->colorspace             = frame->colorspace;\n            enc_ctx->chroma_sample_location = frame->chroma_location;\n        }\n\n        enc_ctx->framerate = ost->frame_rate;\n\n        ost->st->avg_frame_rate = ost->frame_rate;\n\n        // Field order: autodetection\n        if (frame) {\n            if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) &&\n                ost->top_field_first >= 0)\n                frame->top_field_first = !!ost->top_field_first;\n\n            if (frame->interlaced_frame) {\n                if (enc_ctx->codec->id == AV_CODEC_ID_MJPEG)\n                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;\n                else\n                    enc_ctx->field_order = frame->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;\n            } else\n                enc_ctx->field_order = AV_FIELD_PROGRESSIVE;\n        }\n\n        // Field order: override\n        if (ost->top_field_first == 0) {\n            enc_ctx->field_order = AV_FIELD_BB;\n        } else if (ost->top_field_first == 1) {\n            enc_ctx->field_order = AV_FIELD_TT;\n        }\n\n        if (ost->forced_keyframes) {\n            if (!strncmp(ost->forced_keyframes, \"expr:\", 5)) {\n                ret = av_expr_parse(&ost->forced_keyframes_pexpr, ost->forced_keyframes+5,\n                                    forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);\n                if (ret < 0) {\n                    av_log(NULL, AV_LOG_ERROR,\n                           \"Invalid force_key_frames expression '%s'\\n\", ost->forced_keyframes+5);\n                    return ret;\n                }\n                ost->forced_keyframes_expr_const_values[FKF_N] = 0;\n                ost->forced_keyframes_expr_const_values[FKF_N_FORCED] = 0;\n                ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN;\n                ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN;\n\n                // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',\n                // parse it only for static kf timings\n            } else if(strncmp(ost->forced_keyframes, \"source\", 6)) {\n                parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx);\n            }\n        }\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        enc_ctx->time_base = AV_TIME_BASE_Q;\n        if (!enc_ctx->width) {\n            enc_ctx->width     = input_streams[ost->source_index]->st->codecpar->width;\n            enc_ctx->height    = input_streams[ost->source_index]->st->codecpar->height;\n        }\n        break;\n    case AVMEDIA_TYPE_DATA:\n        break;\n    default:\n        abort();\n        break;\n    }\n\n    ost->mux_timebase = enc_ctx->time_base;\n\n    return 0;\n}\n\nstatic int init_output_stream(OutputStream *ost, AVFrame *frame,\n                              char *error, int error_len)\n{\n    int ret = 0;\n\n    if (ost->encoding_needed) {\n        const AVCodec *codec = ost->enc;\n        AVCodecContext *dec = NULL;\n        InputStream *ist;\n\n        ret = init_output_stream_encode(ost, frame);\n        if (ret < 0)\n            return ret;\n\n        if ((ist = get_input_stream(ost)))\n            dec = ist->dec_ctx;\n        if (dec && dec->subtitle_header) {\n            /* ASS code assumes this buffer is null terminated so add extra byte. */\n            ost->enc_ctx->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);\n            if (!ost->enc_ctx->subtitle_header)\n                return AVERROR(ENOMEM);\n            memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);\n            ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;\n        }\n        if (!av_dict_get(ost->encoder_opts, \"threads\", NULL, 0))\n            av_dict_set(&ost->encoder_opts, \"threads\", \"auto\", 0);\n\n        ret = hw_device_setup_for_encode(ost);\n        if (ret < 0) {\n            snprintf(error, error_len, \"Device setup failed for \"\n                     \"encoder on output stream #%d:%d : %s\",\n                     ost->file_index, ost->index, av_err2str(ret));\n            return ret;\n        }\n\n        if (ist && ist->dec->type == AVMEDIA_TYPE_SUBTITLE && ost->enc->type == AVMEDIA_TYPE_SUBTITLE) {\n            int input_props = 0, output_props = 0;\n            AVCodecDescriptor const *input_descriptor =\n                avcodec_descriptor_get(dec->codec_id);\n            AVCodecDescriptor const *output_descriptor =\n                avcodec_descriptor_get(ost->enc_ctx->codec_id);\n            if (input_descriptor)\n                input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);\n            if (output_descriptor)\n                output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);\n            if (input_props && output_props && input_props != output_props) {\n                snprintf(error, error_len,\n                         \"Subtitle encoding currently only possible from text to text \"\n                         \"or bitmap to bitmap\");\n                return AVERROR_INVALIDDATA;\n            }\n        }\n\n        if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {\n            if (ret == AVERROR_EXPERIMENTAL)\n                abort_codec_experimental(codec, 1);\n            snprintf(error, error_len,\n                     \"Error while opening encoder for output stream #%d:%d - \"\n                     \"maybe incorrect parameters such as bit_rate, rate, width or height\",\n                    ost->file_index, ost->index);\n            return ret;\n        }\n        if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&\n            !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))\n            av_buffersink_set_frame_size(ost->filter->filter,\n                                            ost->enc_ctx->frame_size);\n        assert_avoptions(ost->encoder_opts);\n        if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 &&\n            ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */)\n            av_log(NULL, AV_LOG_WARNING, \"The bitrate parameter is set too low.\"\n                                         \" It takes bits/s as argument, not kbits/s\\n\");\n\n        ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc_ctx);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_FATAL,\n                   \"Error initializing the output stream codec context.\\n\");\n            exit_program(1);\n        }\n\n        if (ost->enc_ctx->nb_coded_side_data) {\n            int i;\n\n            for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {\n                const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];\n                uint8_t *dst_data;\n\n                dst_data = av_stream_new_side_data(ost->st, sd_src->type, sd_src->size);\n                if (!dst_data)\n                    return AVERROR(ENOMEM);\n                memcpy(dst_data, sd_src->data, sd_src->size);\n            }\n        }\n\n        /*\n         * Add global input side data. For now this is naive, and copies it\n         * from the input stream's global side data. All side data should\n         * really be funneled over AVFrame and libavfilter, then added back to\n         * packet side data, and then potentially using the first packet for\n         * global side data.\n         */\n        if (ist) {\n            int i;\n            for (i = 0; i < ist->st->nb_side_data; i++) {\n                AVPacketSideData *sd = &ist->st->side_data[i];\n                if (sd->type != AV_PKT_DATA_CPB_PROPERTIES) {\n                    uint8_t *dst = av_stream_new_side_data(ost->st, sd->type, sd->size);\n                    if (!dst)\n                        return AVERROR(ENOMEM);\n                    memcpy(dst, sd->data, sd->size);\n                    if (ist->autorotate && sd->type == AV_PKT_DATA_DISPLAYMATRIX)\n                        av_display_rotation_set((uint32_t *)dst, 0);\n                }\n            }\n        }\n\n        // copy timebase while removing common factors\n        if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)\n            ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});\n\n        // copy estimated duration as a hint to the muxer\n        if (ost->st->duration <= 0 && ist && ist->st->duration > 0)\n            ost->st->duration = av_rescale_q(ist->st->duration, ist->st->time_base, ost->st->time_base);\n    } else if (ost->stream_copy) {\n        ret = init_output_stream_streamcopy(ost);\n        if (ret < 0)\n            return ret;\n    }\n\n    /* initialize bitstream filters for the output stream\n     * needs to be done here, because the codec id for streamcopy is not\n     * known until now */\n    ret = init_output_bsfs(ost);\n    if (ret < 0)\n        return ret;\n\n    ost->initialized = 1;\n\n    ret = of_check_init(output_files[ost->file_index]);\n    if (ret < 0)\n        return ret;\n\n    return ret;\n}\n\nstatic void report_new_stream(int input_index, AVPacket *pkt)\n{\n    InputFile *file = input_files[input_index];\n    AVStream *st = file->ctx->streams[pkt->stream_index];\n\n    if (pkt->stream_index < file->nb_streams_warn)\n        return;\n    av_log(file->ctx, AV_LOG_WARNING,\n           \"New %s stream %d:%d at pos:%\"PRId64\" and DTS:%ss\\n\",\n           av_get_media_type_string(st->codecpar->codec_type),\n           input_index, pkt->stream_index,\n           pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));\n    file->nb_streams_warn = pkt->stream_index + 1;\n}\n\nstatic int transcode_init(void)\n{\n    int ret = 0, i, j, k;\n    AVFormatContext *oc;\n    OutputStream *ost;\n    InputStream *ist;\n    char error[1024] = {0};\n\n    for (i = 0; i < nb_filtergraphs; i++) {\n        FilterGraph *fg = filtergraphs[i];\n        for (j = 0; j < fg->nb_outputs; j++) {\n            OutputFilter *ofilter = fg->outputs[j];\n            if (!ofilter->ost || ofilter->ost->source_index >= 0)\n                continue;\n            if (fg->nb_inputs != 1)\n                continue;\n            for (k = nb_input_streams-1; k >= 0 ; k--)\n                if (fg->inputs[0]->ist == input_streams[k])\n                    break;\n            ofilter->ost->source_index = k;\n        }\n    }\n\n    /* init framerate emulation */\n    for (i = 0; i < nb_input_files; i++) {\n        InputFile *ifile = input_files[i];\n        if (ifile->readrate || ifile->rate_emu)\n            for (j = 0; j < ifile->nb_streams; j++)\n                input_streams[j + ifile->ist_index]->start = av_gettime_relative();\n    }\n\n    /* init input streams */\n    for (i = 0; i < nb_input_streams; i++)\n        if ((ret = init_input_stream(i, error, sizeof(error))) < 0) {\n            for (i = 0; i < nb_output_streams; i++) {\n                ost = output_streams[i];\n                avcodec_close(ost->enc_ctx);\n            }\n            goto dump_format;\n        }\n\n    /*\n     * initialize stream copy and subtitle/data streams.\n     * Encoded AVFrame based streams will get initialized as follows:\n     * - when the first AVFrame is received in do_video_out\n     * - just before the first AVFrame is received in either transcode_step\n     *   or reap_filters due to us requiring the filter chain buffer sink\n     *   to be configured with the correct audio frame size, which is only\n     *   known after the encoder is initialized.\n     */\n    for (i = 0; i < nb_output_streams; i++) {\n        if (!output_streams[i]->stream_copy &&\n            (output_streams[i]->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||\n             output_streams[i]->enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO))\n            continue;\n\n        ret = init_output_stream_wrapper(output_streams[i], NULL, 0);\n        if (ret < 0)\n            goto dump_format;\n    }\n\n    /* discard unused programs */\n    for (i = 0; i < nb_input_files; i++) {\n        InputFile *ifile = input_files[i];\n        for (j = 0; j < ifile->ctx->nb_programs; j++) {\n            AVProgram *p = ifile->ctx->programs[j];\n            int discard  = AVDISCARD_ALL;\n\n            for (k = 0; k < p->nb_stream_indexes; k++)\n                if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) {\n                    discard = AVDISCARD_DEFAULT;\n                    break;\n                }\n            p->discard = discard;\n        }\n    }\n\n    /* write headers for files with no streams */\n    for (i = 0; i < nb_output_files; i++) {\n        oc = output_files[i]->ctx;\n        if (output_files[i]->format->flags & AVFMT_NOSTREAMS && oc->nb_streams == 0) {\n            ret = of_check_init(output_files[i]);\n            if (ret < 0)\n                goto dump_format;\n        }\n    }\n\n dump_format:\n    /* dump the stream mapping */\n    av_log(NULL, AV_LOG_INFO, \"Stream mapping:\\n\");\n    for (i = 0; i < nb_input_streams; i++) {\n        ist = input_streams[i];\n\n        for (j = 0; j < ist->nb_filters; j++) {\n            if (!filtergraph_is_simple(ist->filters[j]->graph)) {\n                av_log(NULL, AV_LOG_INFO, \"  Stream #%d:%d (%s) -> %s\",\n                       ist->file_index, ist->st->index, ist->dec ? ist->dec->name : \"?\",\n                       ist->filters[j]->name);\n                if (nb_filtergraphs > 1)\n                    av_log(NULL, AV_LOG_INFO, \" (graph %d)\", ist->filters[j]->graph->index);\n                av_log(NULL, AV_LOG_INFO, \"\\n\");\n            }\n        }\n    }\n\n    for (i = 0; i < nb_output_streams; i++) {\n        ost = output_streams[i];\n\n        if (ost->attachment_filename) {\n            /* an attached file */\n            av_log(NULL, AV_LOG_INFO, \"  File %s -> Stream #%d:%d\\n\",\n                   ost->attachment_filename, ost->file_index, ost->index);\n            continue;\n        }\n\n        if (ost->filter && !filtergraph_is_simple(ost->filter->graph)) {\n            /* output from a complex graph */\n            av_log(NULL, AV_LOG_INFO, \"  %s\", ost->filter->name);\n            if (nb_filtergraphs > 1)\n                av_log(NULL, AV_LOG_INFO, \" (graph %d)\", ost->filter->graph->index);\n\n            av_log(NULL, AV_LOG_INFO, \" -> Stream #%d:%d (%s)\\n\", ost->file_index,\n                   ost->index, ost->enc ? ost->enc->name : \"?\");\n            continue;\n        }\n\n        av_log(NULL, AV_LOG_INFO, \"  Stream #%d:%d -> #%d:%d\",\n               input_streams[ost->source_index]->file_index,\n               input_streams[ost->source_index]->st->index,\n               ost->file_index,\n               ost->index);\n        if (ost->sync_ist != input_streams[ost->source_index])\n            av_log(NULL, AV_LOG_INFO, \" [sync #%d:%d]\",\n                   ost->sync_ist->file_index,\n                   ost->sync_ist->st->index);\n        if (ost->stream_copy)\n            av_log(NULL, AV_LOG_INFO, \" (copy)\");\n        else {\n            const AVCodec *in_codec    = input_streams[ost->source_index]->dec;\n            const AVCodec *out_codec   = ost->enc;\n            const char *decoder_name   = \"?\";\n            const char *in_codec_name  = \"?\";\n            const char *encoder_name   = \"?\";\n            const char *out_codec_name = \"?\";\n            const AVCodecDescriptor *desc;\n\n            if (in_codec) {\n                decoder_name  = in_codec->name;\n                desc = avcodec_descriptor_get(in_codec->id);\n                if (desc)\n                    in_codec_name = desc->name;\n                if (!strcmp(decoder_name, in_codec_name))\n                    decoder_name = \"native\";\n            }\n\n            if (out_codec) {\n                encoder_name   = out_codec->name;\n                desc = avcodec_descriptor_get(out_codec->id);\n                if (desc)\n                    out_codec_name = desc->name;\n                if (!strcmp(encoder_name, out_codec_name))\n                    encoder_name = \"native\";\n            }\n\n            av_log(NULL, AV_LOG_INFO, \" (%s (%s) -> %s (%s))\",\n                   in_codec_name, decoder_name,\n                   out_codec_name, encoder_name);\n        }\n        av_log(NULL, AV_LOG_INFO, \"\\n\");\n    }\n\n    if (ret) {\n        av_log(NULL, AV_LOG_ERROR, \"%s\\n\", error);\n        return ret;\n    }\n\n    atomic_store(&transcode_init_done, 1);\n\n    return 0;\n}\n\n/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */\nstatic int need_output(void)\n{\n    int i;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost    = output_streams[i];\n        OutputFile *of       = output_files[ost->file_index];\n        AVFormatContext *os  = output_files[ost->file_index]->ctx;\n\n        if (ost->finished ||\n            (os->pb && avio_tell(os->pb) >= of->limit_filesize))\n            continue;\n        if (ost->frame_number >= ost->max_frames) {\n            int j;\n            for (j = 0; j < of->ctx->nb_streams; j++)\n                close_output_stream(output_streams[of->ost_index + j]);\n            continue;\n        }\n\n        return 1;\n    }\n\n    return 0;\n}\n\n/**\n * Select the output stream to process.\n *\n * @return  selected output stream, or NULL if none available\n */\nstatic OutputStream *choose_output(void)\n{\n    int i;\n    int64_t opts_min = INT64_MAX;\n    OutputStream *ost_min = NULL;\n\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n        int64_t opts = ost->last_mux_dts == AV_NOPTS_VALUE ? INT64_MIN :\n                       av_rescale_q(ost->last_mux_dts, ost->st->time_base,\n                                    AV_TIME_BASE_Q);\n        if (ost->last_mux_dts == AV_NOPTS_VALUE)\n            av_log(NULL, AV_LOG_DEBUG,\n                \"cur_dts is invalid st:%d (%d) [init:%d i_done:%d finish:%d] (this is harmless if it occurs once at the start per stream)\\n\",\n                ost->st->index, ost->st->id, ost->initialized, ost->inputs_done, ost->finished);\n\n        if (!ost->initialized && !ost->inputs_done)\n            return ost->unavailable ? NULL : ost;\n\n        if (!ost->finished && opts < opts_min) {\n            opts_min = opts;\n            ost_min  = ost->unavailable ? NULL : ost;\n        }\n    }\n    return ost_min;\n}\n\nstatic void set_tty_echo(int on)\n{\n#if HAVE_TERMIOS_H\n    struct termios tty;\n    if (tcgetattr(0, &tty) == 0) {\n        if (on) tty.c_lflag |= ECHO;\n        else    tty.c_lflag &= ~ECHO;\n        tcsetattr(0, TCSANOW, &tty);\n    }\n#endif\n}\n\nstatic int check_keyboard_interaction(int64_t cur_time)\n{\n    int i, ret, key;\n    static int64_t last_time;\n    if (received_nb_signals)\n        return AVERROR_EXIT;\n    /* read_key() returns 0 on EOF */\n    if (cur_time - last_time >= 100000) {\n        key =  read_key();\n        last_time = cur_time;\n    }else\n        key = -1;\n    if (key == 'q') {\n        av_log(NULL, AV_LOG_INFO, \"\\n\\n[q] command received. Exiting.\\n\\n\");\n        return AVERROR_EXIT;\n    }\n    if (key == '+') av_log_set_level(av_log_get_level()+10);\n    if (key == '-') av_log_set_level(av_log_get_level()-10);\n    if (key == 's') qp_hist     ^= 1;\n    if (key == 'h'){\n        if (do_hex_dump){\n            do_hex_dump = do_pkt_dump = 0;\n        } else if(do_pkt_dump){\n            do_hex_dump = 1;\n        } else\n            do_pkt_dump = 1;\n        av_log_set_level(AV_LOG_DEBUG);\n    }\n    if (key == 'c' || key == 'C'){\n        char buf[4096], target[64], command[256], arg[256] = {0};\n        double time;\n        int k, n = 0;\n        fprintf(stderr, \"\\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\\n\");\n        i = 0;\n        set_tty_echo(1);\n        while ((k = read_key()) != '\\n' && k != '\\r' && i < sizeof(buf)-1)\n            if (k > 0)\n                buf[i++] = k;\n        buf[i] = 0;\n        set_tty_echo(0);\n        fprintf(stderr, \"\\n\");\n        if (k > 0 &&\n            (n = sscanf(buf, \"%63[^ ] %lf %255[^ ] %255[^\\n]\", target, &time, command, arg)) >= 3) {\n            av_log(NULL, AV_LOG_DEBUG, \"Processing command target:%s time:%f command:%s arg:%s\",\n                   target, time, command, arg);\n            for (i = 0; i < nb_filtergraphs; i++) {\n                FilterGraph *fg = filtergraphs[i];\n                if (fg->graph) {\n                    if (time < 0) {\n                        ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),\n                                                          key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);\n                        fprintf(stderr, \"Command reply for stream %d: ret:%d res:\\n%s\", i, ret, buf);\n                    } else if (key == 'c') {\n                        fprintf(stderr, \"Queuing commands only on filters supporting the specific command is unsupported\\n\");\n                        ret = AVERROR_PATCHWELCOME;\n                    } else {\n                        ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);\n                        if (ret < 0)\n                            fprintf(stderr, \"Queuing command failed with error %s\\n\", av_err2str(ret));\n                    }\n                }\n            }\n        } else {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Parse error, at least 3 arguments were expected, \"\n                   \"only %d given in string '%s'\\n\", n, buf);\n        }\n    }\n    if (key == 'd' || key == 'D'){\n        int debug=0;\n        if(key == 'D') {\n            debug = input_streams[0]->dec_ctx->debug << 1;\n            if(!debug) debug = 1;\n            while (debug & FF_DEBUG_DCT_COEFF) //unsupported, would just crash\n                debug += debug;\n        }else{\n            char buf[32];\n            int k = 0;\n            i = 0;\n            set_tty_echo(1);\n            while ((k = read_key()) != '\\n' && k != '\\r' && i < sizeof(buf)-1)\n                if (k > 0)\n                    buf[i++] = k;\n            buf[i] = 0;\n            set_tty_echo(0);\n            fprintf(stderr, \"\\n\");\n            if (k <= 0 || sscanf(buf, \"%d\", &debug)!=1)\n                fprintf(stderr,\"error parsing debug value\\n\");\n        }\n        for(i=0;i<nb_input_streams;i++) {\n            input_streams[i]->dec_ctx->debug = debug;\n        }\n        for(i=0;i<nb_output_streams;i++) {\n            OutputStream *ost = output_streams[i];\n            ost->enc_ctx->debug = debug;\n        }\n        if(debug) av_log_set_level(AV_LOG_DEBUG);\n        fprintf(stderr,\"debug=%d\\n\", debug);\n    }\n    if (key == '?'){\n        fprintf(stderr, \"key    function\\n\"\n                        \"?      show this help\\n\"\n                        \"+      increase verbosity\\n\"\n                        \"-      decrease verbosity\\n\"\n                        \"c      Send command to first matching filter supporting it\\n\"\n                        \"C      Send/Queue command to all matching filters\\n\"\n                        \"D      cycle through available debug modes\\n\"\n                        \"h      dump packets/hex press to cycle through the 3 states\\n\"\n                        \"q      quit\\n\"\n                        \"s      Show QP histogram\\n\"\n        );\n    }\n    return 0;\n}\n\n#if HAVE_THREADS\nstatic void *input_thread(void *arg)\n{\n    InputFile *f = arg;\n    AVPacket *pkt = f->pkt, *queue_pkt;\n    unsigned flags = f->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0;\n    int ret = 0;\n\n    while (1) {\n        ret = av_read_frame(f->ctx, pkt);\n\n        if (ret == AVERROR(EAGAIN)) {\n            av_usleep(10000);\n            continue;\n        }\n        if (ret < 0) {\n            av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);\n            break;\n        }\n        queue_pkt = av_packet_alloc();\n        if (!queue_pkt) {\n            av_packet_unref(pkt);\n            av_thread_message_queue_set_err_recv(f->in_thread_queue, AVERROR(ENOMEM));\n            break;\n        }\n        av_packet_move_ref(queue_pkt, pkt);\n        ret = av_thread_message_queue_send(f->in_thread_queue, &queue_pkt, flags);\n        if (flags && ret == AVERROR(EAGAIN)) {\n            flags = 0;\n            ret = av_thread_message_queue_send(f->in_thread_queue, &queue_pkt, flags);\n            av_log(f->ctx, AV_LOG_WARNING,\n                   \"Thread message queue blocking; consider raising the \"\n                   \"thread_queue_size option (current value: %d)\\n\",\n                   f->thread_queue_size);\n        }\n        if (ret < 0) {\n            if (ret != AVERROR_EOF)\n                av_log(f->ctx, AV_LOG_ERROR,\n                       \"Unable to send packet to main thread: %s\\n\",\n                       av_err2str(ret));\n            av_packet_free(&queue_pkt);\n            av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);\n            break;\n        }\n    }\n\n    return NULL;\n}\n\nstatic void free_input_thread(int i)\n{\n    InputFile *f = input_files[i];\n    AVPacket *pkt;\n\n    if (!f || !f->in_thread_queue)\n        return;\n    av_thread_message_queue_set_err_send(f->in_thread_queue, AVERROR_EOF);\n    while (av_thread_message_queue_recv(f->in_thread_queue, &pkt, 0) >= 0)\n        av_packet_free(&pkt);\n\n    pthread_join(f->thread, NULL);\n    f->joined = 1;\n    av_thread_message_queue_free(&f->in_thread_queue);\n}\n\nstatic void free_input_threads(void)\n{\n    int i;\n\n    for (i = 0; i < nb_input_files; i++)\n        free_input_thread(i);\n}\n\nstatic int init_input_thread(int i)\n{\n    int ret;\n    InputFile *f = input_files[i];\n\n    if (f->thread_queue_size < 0)\n        f->thread_queue_size = (nb_input_files > 1 ? 8 : 0);\n    if (!f->thread_queue_size)\n        return 0;\n\n    if (f->ctx->pb ? !f->ctx->pb->seekable :\n        strcmp(f->ctx->iformat->name, \"lavfi\"))\n        f->non_blocking = 1;\n    ret = av_thread_message_queue_alloc(&f->in_thread_queue,\n                                        f->thread_queue_size, sizeof(f->pkt));\n    if (ret < 0)\n        return ret;\n\n    if ((ret = pthread_create(&f->thread, NULL, input_thread, f))) {\n        av_log(NULL, AV_LOG_ERROR, \"pthread_create failed: %s. Try to increase `ulimit -v` or decrease `ulimit -s`.\\n\", strerror(ret));\n        av_thread_message_queue_free(&f->in_thread_queue);\n        return AVERROR(ret);\n    }\n\n    return 0;\n}\n\nstatic int init_input_threads(void)\n{\n    int i, ret;\n\n    for (i = 0; i < nb_input_files; i++) {\n        ret = init_input_thread(i);\n        if (ret < 0)\n            return ret;\n    }\n    return 0;\n}\n\nstatic int get_input_packet_mt(InputFile *f, AVPacket **pkt)\n{\n    return av_thread_message_queue_recv(f->in_thread_queue, pkt,\n                                        f->non_blocking ?\n                                        AV_THREAD_MESSAGE_NONBLOCK : 0);\n}\n#endif\n\nstatic int get_input_packet(InputFile *f, AVPacket **pkt)\n{\n    if (f->readrate || f->rate_emu) {\n        int i;\n        int64_t file_start = copy_ts * (\n                              (f->ctx->start_time != AV_NOPTS_VALUE ? f->ctx->start_time * !start_at_zero : 0) +\n                              (f->start_time != AV_NOPTS_VALUE ? f->start_time : 0)\n                             );\n        float scale = f->rate_emu ? 1.0 : f->readrate;\n        for (i = 0; i < f->nb_streams; i++) {\n            InputStream *ist = input_streams[f->ist_index + i];\n            int64_t stream_ts_offset, pts, now;\n            if (!ist->nb_packets || (ist->decoding_needed && !ist->got_output)) continue;\n            stream_ts_offset = FFMAX(ist->first_dts != AV_NOPTS_VALUE ? ist->first_dts : 0, file_start);\n            pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);\n            now = (av_gettime_relative() - ist->start) * scale + stream_ts_offset;\n            if (pts > now)\n                return AVERROR(EAGAIN);\n        }\n    }\n\n#if HAVE_THREADS\n    if (f->thread_queue_size)\n        return get_input_packet_mt(f, pkt);\n#endif\n    *pkt = f->pkt;\n    return av_read_frame(f->ctx, *pkt);\n}\n\nstatic int got_eagain(void)\n{\n    int i;\n    for (i = 0; i < nb_output_streams; i++)\n        if (output_streams[i]->unavailable)\n            return 1;\n    return 0;\n}\n\nstatic void reset_eagain(void)\n{\n    int i;\n    for (i = 0; i < nb_input_files; i++)\n        input_files[i]->eagain = 0;\n    for (i = 0; i < nb_output_streams; i++)\n        output_streams[i]->unavailable = 0;\n}\n\n// set duration to max(tmp, duration) in a proper time base and return duration's time_base\nstatic AVRational duration_max(int64_t tmp, int64_t *duration, AVRational tmp_time_base,\n                               AVRational time_base)\n{\n    int ret;\n\n    if (!*duration) {\n        *duration = tmp;\n        return tmp_time_base;\n    }\n\n    ret = av_compare_ts(*duration, time_base, tmp, tmp_time_base);\n    if (ret < 0) {\n        *duration = tmp;\n        return tmp_time_base;\n    }\n\n    return time_base;\n}\n\nstatic int seek_to_start(InputFile *ifile, AVFormatContext *is)\n{\n    InputStream *ist;\n    AVCodecContext *avctx;\n    int i, ret, has_audio = 0;\n    int64_t duration = 0;\n\n    ret = avformat_seek_file(is, -1, INT64_MIN, is->start_time, is->start_time, 0);\n    if (ret < 0)\n        return ret;\n\n    for (i = 0; i < ifile->nb_streams; i++) {\n        ist   = input_streams[ifile->ist_index + i];\n        avctx = ist->dec_ctx;\n\n        /* duration is the length of the last frame in a stream\n         * when audio stream is present we don't care about\n         * last video frame length because it's not defined exactly */\n        if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples)\n            has_audio = 1;\n    }\n\n    for (i = 0; i < ifile->nb_streams; i++) {\n        ist   = input_streams[ifile->ist_index + i];\n        avctx = ist->dec_ctx;\n\n        if (has_audio) {\n            if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples) {\n                AVRational sample_rate = {1, avctx->sample_rate};\n\n                duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base);\n            } else {\n                continue;\n            }\n        } else {\n            if (ist->framerate.num) {\n                duration = av_rescale_q(1, av_inv_q(ist->framerate), ist->st->time_base);\n            } else if (ist->st->avg_frame_rate.num) {\n                duration = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate), ist->st->time_base);\n            } else {\n                duration = 1;\n            }\n        }\n        if (!ifile->duration)\n            ifile->time_base = ist->st->time_base;\n        /* the total duration of the stream, max_pts - min_pts is\n         * the duration of the stream without the last frame */\n        if (ist->max_pts > ist->min_pts && ist->max_pts - (uint64_t)ist->min_pts < INT64_MAX - duration)\n            duration += ist->max_pts - ist->min_pts;\n        ifile->time_base = duration_max(duration, &ifile->duration, ist->st->time_base,\n                                        ifile->time_base);\n    }\n\n    if (ifile->loop > 0)\n        ifile->loop--;\n\n    return ret;\n}\n\n/*\n * Return\n * - 0 -- one packet was read and processed\n * - AVERROR(EAGAIN) -- no packets were available for selected file,\n *   this function should be called again\n * - AVERROR_EOF -- this function should not be called again\n */\nstatic int process_input(int file_index)\n{\n    InputFile *ifile = input_files[file_index];\n    AVFormatContext *is;\n    InputStream *ist;\n    AVPacket *pkt;\n    int ret, thread_ret, i, j;\n    int64_t duration;\n    int64_t pkt_dts;\n    int disable_discontinuity_correction = copy_ts;\n\n    is  = ifile->ctx;\n    ret = get_input_packet(ifile, &pkt);\n\n    if (ret == AVERROR(EAGAIN)) {\n        ifile->eagain = 1;\n        return ret;\n    }\n    if (ret < 0 && ifile->loop) {\n        AVCodecContext *avctx;\n        for (i = 0; i < ifile->nb_streams; i++) {\n            ist = input_streams[ifile->ist_index + i];\n            avctx = ist->dec_ctx;\n            if (ist->processing_needed) {\n                ret = process_input_packet(ist, NULL, 1);\n                if (ret>0)\n                    return 0;\n                if (ist->decoding_needed)\n                    avcodec_flush_buffers(avctx);\n            }\n        }\n#if HAVE_THREADS\n        free_input_thread(file_index);\n#endif\n        ret = seek_to_start(ifile, is);\n#if HAVE_THREADS\n        thread_ret = init_input_thread(file_index);\n        if (thread_ret < 0)\n            return thread_ret;\n#endif\n        if (ret < 0)\n            av_log(NULL, AV_LOG_WARNING, \"Seek to start failed.\\n\");\n        else\n            ret = get_input_packet(ifile, &pkt);\n        if (ret == AVERROR(EAGAIN)) {\n            ifile->eagain = 1;\n            return ret;\n        }\n    }\n    if (ret < 0) {\n        if (ret != AVERROR_EOF) {\n            print_error(is->url, ret);\n            if (exit_on_error)\n                exit_program(1);\n        }\n\n        for (i = 0; i < ifile->nb_streams; i++) {\n            ist = input_streams[ifile->ist_index + i];\n            if (ist->processing_needed) {\n                ret = process_input_packet(ist, NULL, 0);\n                if (ret>0)\n                    return 0;\n            }\n\n            /* mark all outputs that don't go through lavfi as finished */\n            for (j = 0; j < nb_output_streams; j++) {\n                OutputStream *ost = output_streams[j];\n\n                if (ost->source_index == ifile->ist_index + i &&\n                    (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))\n                    finish_output_stream(ost);\n            }\n        }\n\n        ifile->eof_reached = 1;\n        return AVERROR(EAGAIN);\n    }\n\n    reset_eagain();\n\n    if (do_pkt_dump) {\n        av_pkt_dump_log2(NULL, AV_LOG_INFO, pkt, do_hex_dump,\n                         is->streams[pkt->stream_index]);\n    }\n    /* the following test is needed in case new streams appear\n       dynamically in stream : we ignore them */\n    if (pkt->stream_index >= ifile->nb_streams) {\n        report_new_stream(file_index, pkt);\n        goto discard_packet;\n    }\n\n    ist = input_streams[ifile->ist_index + pkt->stream_index];\n\n    ist->data_size += pkt->size;\n    ist->nb_packets++;\n\n    if (ist->discard)\n        goto discard_packet;\n\n    if (pkt->flags & AV_PKT_FLAG_CORRUPT) {\n        av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,\n               \"%s: corrupt input packet in stream %d\\n\", is->url, pkt->stream_index);\n        if (exit_on_error)\n            exit_program(1);\n    }\n\n    if (debug_ts) {\n        av_log(NULL, AV_LOG_INFO, \"demuxer -> ist_index:%d type:%s \"\n               \"next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\\n\",\n               ifile->ist_index + pkt->stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),\n               av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),\n               av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),\n               av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ist->st->time_base),\n               av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ist->st->time_base),\n               av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ist->st->time_base),\n               av_ts2str(input_files[ist->file_index]->ts_offset),\n               av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));\n    }\n\n    if(!ist->wrap_correction_done && is->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){\n        int64_t stime, stime2;\n        // Correcting starttime based on the enabled streams\n        // FIXME this ideally should be done before the first use of starttime but we do not know which are the enabled streams at that point.\n        //       so we instead do it here as part of discontinuity handling\n        if (   ist->next_dts == AV_NOPTS_VALUE\n            && ifile->ts_offset == -is->start_time\n            && (is->iformat->flags & AVFMT_TS_DISCONT)) {\n            int64_t new_start_time = INT64_MAX;\n            for (i=0; i<is->nb_streams; i++) {\n                AVStream *st = is->streams[i];\n                if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)\n                    continue;\n                new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));\n            }\n            if (new_start_time > is->start_time) {\n                av_log(is, AV_LOG_VERBOSE, \"Correcting start time by %\"PRId64\"\\n\", new_start_time - is->start_time);\n                ifile->ts_offset = -new_start_time;\n            }\n        }\n\n        stime = av_rescale_q(is->start_time, AV_TIME_BASE_Q, ist->st->time_base);\n        stime2= stime + (1ULL<<ist->st->pts_wrap_bits);\n        ist->wrap_correction_done = 1;\n\n        if(stime2 > stime && pkt->dts != AV_NOPTS_VALUE && pkt->dts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {\n            pkt->dts -= 1ULL<<ist->st->pts_wrap_bits;\n            ist->wrap_correction_done = 0;\n        }\n        if(stime2 > stime && pkt->pts != AV_NOPTS_VALUE && pkt->pts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {\n            pkt->pts -= 1ULL<<ist->st->pts_wrap_bits;\n            ist->wrap_correction_done = 0;\n        }\n    }\n\n    /* add the stream-global side data to the first packet */\n    if (ist->nb_packets == 1) {\n        for (i = 0; i < ist->st->nb_side_data; i++) {\n            AVPacketSideData *src_sd = &ist->st->side_data[i];\n            uint8_t *dst_data;\n\n            if (src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)\n                continue;\n\n            if (av_packet_get_side_data(pkt, src_sd->type, NULL))\n                continue;\n\n            dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size);\n            if (!dst_data)\n                exit_program(1);\n\n            memcpy(dst_data, src_sd->data, src_sd->size);\n        }\n    }\n\n    if (pkt->dts != AV_NOPTS_VALUE)\n        pkt->dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);\n    if (pkt->pts != AV_NOPTS_VALUE)\n        pkt->pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);\n\n    if (pkt->pts != AV_NOPTS_VALUE)\n        pkt->pts *= ist->ts_scale;\n    if (pkt->dts != AV_NOPTS_VALUE)\n        pkt->dts *= ist->ts_scale;\n\n    pkt_dts = av_rescale_q_rnd(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);\n    if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||\n         ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&\n        pkt_dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts\n        && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {\n        int64_t delta   = pkt_dts - ifile->last_ts;\n        if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||\n            delta >  1LL*dts_delta_threshold*AV_TIME_BASE){\n            ifile->ts_offset -= delta;\n            av_log(NULL, AV_LOG_DEBUG,\n                   \"Inter stream timestamp discontinuity %\"PRId64\", new offset= %\"PRId64\"\\n\",\n                   delta, ifile->ts_offset);\n            pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);\n            if (pkt->pts != AV_NOPTS_VALUE)\n                pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);\n        }\n    }\n\n    duration = av_rescale_q(ifile->duration, ifile->time_base, ist->st->time_base);\n    if (pkt->pts != AV_NOPTS_VALUE) {\n        pkt->pts += duration;\n        ist->max_pts = FFMAX(pkt->pts, ist->max_pts);\n        ist->min_pts = FFMIN(pkt->pts, ist->min_pts);\n    }\n\n    if (pkt->dts != AV_NOPTS_VALUE)\n        pkt->dts += duration;\n\n    pkt_dts = av_rescale_q_rnd(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);\n\n    if (copy_ts && pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&\n        (is->iformat->flags & AVFMT_TS_DISCONT) && ist->st->pts_wrap_bits < 60) {\n        int64_t wrap_dts = av_rescale_q_rnd(pkt->dts + (1LL<<ist->st->pts_wrap_bits),\n                                            ist->st->time_base, AV_TIME_BASE_Q,\n                                            AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);\n        if (FFABS(wrap_dts - ist->next_dts) < FFABS(pkt_dts - ist->next_dts)/10)\n            disable_discontinuity_correction = 0;\n    }\n\n    if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||\n         ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&\n         pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&\n        !disable_discontinuity_correction) {\n        int64_t delta   = pkt_dts - ist->next_dts;\n        if (is->iformat->flags & AVFMT_TS_DISCONT) {\n            if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||\n                delta >  1LL*dts_delta_threshold*AV_TIME_BASE ||\n                pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {\n                ifile->ts_offset -= delta;\n                av_log(NULL, AV_LOG_DEBUG,\n                       \"timestamp discontinuity for stream #%d:%d \"\n                       \"(id=%d, type=%s): %\"PRId64\", new offset= %\"PRId64\"\\n\",\n                       ist->file_index, ist->st->index, ist->st->id,\n                       av_get_media_type_string(ist->dec_ctx->codec_type),\n                       delta, ifile->ts_offset);\n                pkt->dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);\n                if (pkt->pts != AV_NOPTS_VALUE)\n                    pkt->pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);\n            }\n        } else {\n            if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||\n                 delta >  1LL*dts_error_threshold*AV_TIME_BASE) {\n                av_log(NULL, AV_LOG_WARNING, \"DTS %\"PRId64\", next:%\"PRId64\" st:%d invalid dropping\\n\", pkt->dts, ist->next_dts, pkt->stream_index);\n                pkt->dts = AV_NOPTS_VALUE;\n            }\n            if (pkt->pts != AV_NOPTS_VALUE){\n                int64_t pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);\n                delta   = pkt_pts - ist->next_dts;\n                if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||\n                     delta >  1LL*dts_error_threshold*AV_TIME_BASE) {\n                    av_log(NULL, AV_LOG_WARNING, \"PTS %\"PRId64\", next:%\"PRId64\" invalid dropping st:%d\\n\", pkt->pts, ist->next_dts, pkt->stream_index);\n                    pkt->pts = AV_NOPTS_VALUE;\n                }\n            }\n        }\n    }\n\n    if (pkt->dts != AV_NOPTS_VALUE)\n        ifile->last_ts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);\n\n    if (debug_ts) {\n        av_log(NULL, AV_LOG_INFO, \"demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\\n\",\n               ifile->ist_index + pkt->stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),\n               av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ist->st->time_base),\n               av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ist->st->time_base),\n               av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ist->st->time_base),\n               av_ts2str(input_files[ist->file_index]->ts_offset),\n               av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));\n    }\n\n    sub2video_heartbeat(ist, pkt->pts);\n\n    process_input_packet(ist, pkt, 0);\n\ndiscard_packet:\n#if HAVE_THREADS\n    if (ifile->thread_queue_size)\n        av_packet_free(&pkt);\n    else\n#endif\n    av_packet_unref(pkt);\n\n    return 0;\n}\n\n/**\n * Perform a step of transcoding for the specified filter graph.\n *\n * @param[in]  graph     filter graph to consider\n * @param[out] best_ist  input stream where a frame would allow to continue\n * @return  0 for success, <0 for error\n */\nstatic int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)\n{\n    int i, ret;\n    int nb_requests, nb_requests_max = 0;\n    InputFilter *ifilter;\n    InputStream *ist;\n\n    *best_ist = NULL;\n    ret = avfilter_graph_request_oldest(graph->graph);\n    if (ret >= 0)\n        return reap_filters(0);\n\n    if (ret == AVERROR_EOF) {\n        ret = reap_filters(1);\n        for (i = 0; i < graph->nb_outputs; i++)\n            close_output_stream(graph->outputs[i]->ost);\n        return ret;\n    }\n    if (ret != AVERROR(EAGAIN))\n        return ret;\n\n    for (i = 0; i < graph->nb_inputs; i++) {\n        ifilter = graph->inputs[i];\n        ist = ifilter->ist;\n        if (input_files[ist->file_index]->eagain ||\n            input_files[ist->file_index]->eof_reached)\n            continue;\n        nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter);\n        if (nb_requests > nb_requests_max) {\n            nb_requests_max = nb_requests;\n            *best_ist = ist;\n        }\n    }\n\n    if (!*best_ist)\n        for (i = 0; i < graph->nb_outputs; i++)\n            graph->outputs[i]->ost->unavailable = 1;\n\n    return 0;\n}\n\n/**\n * Run a single step of transcoding.\n *\n * @return  0 for success, <0 for error\n */\nstatic int transcode_step(void)\n{\n    OutputStream *ost;\n    InputStream  *ist = NULL;\n    int ret;\n\n    ost = choose_output();\n    if (!ost) {\n        if (got_eagain()) {\n            reset_eagain();\n            av_usleep(10000);\n            return 0;\n        }\n        av_log(NULL, AV_LOG_VERBOSE, \"No more inputs to read from, finishing.\\n\");\n        return AVERROR_EOF;\n    }\n\n    if (ost->filter && !ost->filter->graph->graph) {\n        if (ifilter_has_all_input_formats(ost->filter->graph)) {\n            ret = configure_filtergraph(ost->filter->graph);\n            if (ret < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"Error reinitializing filters!\\n\");\n                return ret;\n            }\n        }\n    }\n\n    if (ost->filter && ost->filter->graph->graph) {\n        /*\n         * Similar case to the early audio initialization in reap_filters.\n         * Audio is special in ffmpeg.c currently as we depend on lavfi's\n         * audio frame buffering/creation to get the output audio frame size\n         * in samples correct. The audio frame size for the filter chain is\n         * configured during the output stream initialization.\n         *\n         * Apparently avfilter_graph_request_oldest (called in\n         * transcode_from_filter just down the line) peeks. Peeking already\n         * puts one frame \"ready to be given out\", which means that any\n         * update in filter buffer sink configuration afterwards will not\n         * help us. And yes, even if it would be utilized,\n         * av_buffersink_get_samples is affected, as it internally utilizes\n         * the same early exit for peeked frames.\n         *\n         * In other words, if avfilter_graph_request_oldest would not make\n         * further filter chain configuration or usage of\n         * av_buffersink_get_samples useless (by just causing the return\n         * of the peeked AVFrame as-is), we could get rid of this additional\n         * early encoder initialization.\n         */\n        if (av_buffersink_get_type(ost->filter->filter) == AVMEDIA_TYPE_AUDIO)\n            init_output_stream_wrapper(ost, NULL, 1);\n\n        if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0)\n            return ret;\n        if (!ist)\n            return 0;\n    } else if (ost->filter) {\n        int i;\n        for (i = 0; i < ost->filter->graph->nb_inputs; i++) {\n            InputFilter *ifilter = ost->filter->graph->inputs[i];\n            if (!ifilter->ist->got_output && !input_files[ifilter->ist->file_index]->eof_reached) {\n                ist = ifilter->ist;\n                break;\n            }\n        }\n        if (!ist) {\n            ost->inputs_done = 1;\n            return 0;\n        }\n    } else {\n        av_assert0(ost->source_index >= 0);\n        ist = input_streams[ost->source_index];\n    }\n\n    ret = process_input(ist->file_index);\n    if (ret == AVERROR(EAGAIN)) {\n        if (input_files[ist->file_index]->eagain)\n            ost->unavailable = 1;\n        return 0;\n    }\n\n    if (ret < 0)\n        return ret == AVERROR_EOF ? 0 : ret;\n\n    return reap_filters(0);\n}\n\n/* is_timeout checks if transcode() is running longer\n * than a timeout value, return 1 when timeout.\n */\nEM_JS(int, is_timeout, (int64_t diff), {\n    if (Module.timeout === -1) return 0;\n    else {\n      return Module.timeout <= diff;\n    }\n});\n\n/*\n * The following code is the main loop of the file converter\n */\nstatic int transcode(void)\n{\n    int ret, i;\n    AVFormatContext *os;\n    OutputStream *ost;\n    InputStream *ist;\n    int64_t timer_start;\n    int64_t total_packets_written = 0;\n\n    ret = transcode_init();\n    if (ret < 0)\n        goto fail;\n\n    if (stdin_interaction) {\n        av_log(NULL, AV_LOG_INFO, \"Press [q] to stop, [?] for help\\n\");\n    }\n\n    timer_start = av_gettime_relative();\n\n#if HAVE_THREADS\n    if ((ret = init_input_threads()) < 0)\n        goto fail;\n#endif\n\n    while (!received_sigterm) {\n        int64_t cur_time= av_gettime_relative();\n\n        if (is_timeout((cur_time - timer_start) / 1000) == 1) exit_program(1);\n\n        /* if 'q' pressed, exits */\n        if (stdin_interaction)\n            if (check_keyboard_interaction(cur_time) < 0)\n                break;\n\n        /* check if there's any stream where output is still needed */\n        if (!need_output()) {\n            av_log(NULL, AV_LOG_VERBOSE, \"No more output streams to write to, finishing.\\n\");\n            break;\n        }\n\n        ret = transcode_step();\n        if (ret < 0 && ret != AVERROR_EOF) {\n            av_log(NULL, AV_LOG_ERROR, \"Error while filtering: %s\\n\", av_err2str(ret));\n            break;\n        }\n\n        /* dump report by using the output first video and audio streams */\n        print_report(0, timer_start, cur_time);\n    }\n#if HAVE_THREADS\n    free_input_threads();\n#endif\n\n    /* at the end of stream, we must flush the decoder buffers */\n    for (i = 0; i < nb_input_streams; i++) {\n        ist = input_streams[i];\n        if (!input_files[ist->file_index]->eof_reached) {\n            process_input_packet(ist, NULL, 0);\n        }\n    }\n    flush_encoders();\n\n    term_exit();\n\n    /* write the trailer if needed */\n    for (i = 0; i < nb_output_files; i++) {\n        ret = of_write_trailer(output_files[i]);\n        if (ret < 0 && exit_on_error)\n            exit_program(1);\n    }\n\n    /* dump report by using the first video and audio streams */\n    print_report(1, timer_start, av_gettime_relative());\n\n    /* close the output files */\n    for (i = 0; i < nb_output_files; i++) {\n        os = output_files[i]->ctx;\n        if (os && os->oformat && !(os->oformat->flags & AVFMT_NOFILE)) {\n            if ((ret = avio_closep(&os->pb)) < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"Error closing file %s: %s\\n\", os->url, av_err2str(ret));\n                if (exit_on_error)\n                    exit_program(1);\n            }\n        }\n    }\n\n    /* close each encoder */\n    for (i = 0; i < nb_output_streams; i++) {\n        ost = output_streams[i];\n        if (ost->encoding_needed) {\n            av_freep(&ost->enc_ctx->stats_in);\n        }\n        total_packets_written += ost->packets_written;\n        if (!ost->packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM)) {\n            av_log(NULL, AV_LOG_FATAL, \"Empty output on stream %d.\\n\", i);\n            exit_program(1);\n        }\n    }\n\n    if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {\n        av_log(NULL, AV_LOG_FATAL, \"Empty output\\n\");\n        exit_program(1);\n    }\n\n    /* close each decoder */\n    for (i = 0; i < nb_input_streams; i++) {\n        ist = input_streams[i];\n        if (ist->decoding_needed) {\n            avcodec_close(ist->dec_ctx);\n            if (ist->hwaccel_uninit)\n                ist->hwaccel_uninit(ist->dec_ctx);\n        }\n    }\n\n    hw_device_free_all();\n\n    /* finished ! */\n    ret = 0;\n\n fail:\n#if HAVE_THREADS\n    free_input_threads();\n#endif\n\n    if (output_streams) {\n        for (i = 0; i < nb_output_streams; i++) {\n            ost = output_streams[i];\n            if (ost) {\n                if (ost->logfile) {\n                    if (fclose(ost->logfile))\n                        av_log(NULL, AV_LOG_ERROR,\n                               \"Error closing logfile, loss of information possible: %s\\n\",\n                               av_err2str(AVERROR(errno)));\n                    ost->logfile = NULL;\n                }\n                av_freep(&ost->forced_kf_pts);\n                av_freep(&ost->apad);\n                av_freep(&ost->disposition);\n                av_dict_free(&ost->encoder_opts);\n                av_dict_free(&ost->sws_dict);\n                av_dict_free(&ost->swr_opts);\n            }\n        }\n    }\n    return ret;\n}\n\nstatic BenchmarkTimeStamps get_benchmark_time_stamps(void)\n{\n    BenchmarkTimeStamps time_stamps = { av_gettime_relative() };\n#if HAVE_GETRUSAGE\n    struct rusage rusage;\n\n    getrusage(RUSAGE_SELF, &rusage);\n    time_stamps.user_usec =\n        (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;\n    time_stamps.sys_usec =\n        (rusage.ru_stime.tv_sec * 1000000LL) + rusage.ru_stime.tv_usec;\n#elif HAVE_GETPROCESSTIMES\n    HANDLE proc;\n    FILETIME c, e, k, u;\n    proc = GetCurrentProcess();\n    GetProcessTimes(proc, &c, &e, &k, &u);\n    time_stamps.user_usec =\n        ((int64_t)u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;\n    time_stamps.sys_usec =\n        ((int64_t)k.dwHighDateTime << 32 | k.dwLowDateTime) / 10;\n#else\n    time_stamps.user_usec = time_stamps.sys_usec = 0;\n#endif\n    return time_stamps;\n}\n\nstatic int64_t getmaxrss(void)\n{\n#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS\n    struct rusage rusage;\n    getrusage(RUSAGE_SELF, &rusage);\n    return (int64_t)rusage.ru_maxrss * 1024;\n#elif HAVE_GETPROCESSMEMORYINFO\n    HANDLE proc;\n    PROCESS_MEMORY_COUNTERS memcounters;\n    proc = GetCurrentProcess();\n    memcounters.cb = sizeof(memcounters);\n    GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));\n    return memcounters.PeakPagefileUsage;\n#else\n    return 0;\n#endif\n}\n\n/* init_globals initializes global variables to enable multiple\n * calls of ffmpeg().\n *\n * This is not required in the original command line version as\n * the global varialbes are always re-initialized when calling\n * main() function.\n */\nvoid init_globals() {\n  nb_frames_dup = 0;\n  dup_warning = 1000;\n  nb_frames_drop = 0;\n  nb_output_dumped = 0;\n  want_sdp = 1;\n\n  progress_avio = NULL;\n\n  input_streams = NULL;\n  nb_input_streams = 0;\n  input_files = NULL;\n  nb_input_files = 0;\n\n  output_streams = NULL;\n  nb_output_streams = 0;\n  output_files = NULL;\n  nb_output_files = 0;\n\n  filtergraphs = NULL;\n  nb_filtergraphs = 0;\n\n  received_sigterm = 0;\n  received_nb_signals = 0;\n  transcode_init_done = ATOMIC_VAR_INIT(0);\n  ffmpeg_exited = 0;\n  main_return_code = 0;\n  copy_ts_first_pts = AV_NOPTS_VALUE;\n}\n\n/* ffmpeg() is simply a rename of main(), but it makes things easier to\n * control as main() is a special function name that might trigger\n * some hidden mechanisms.\n *\n * One example is that when using multi-threading, a proxy_main() function\n * might be used instead of main().\n */\nint ffmpeg(int argc, char **argv)\n// int main(int argc, char **argv)\n{\n    init_globals();\n\n    int i, ret;\n    BenchmarkTimeStamps ti;\n\n    init_dynload();\n\n    register_exit(ffmpeg_cleanup);\n\n    setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */\n\n    av_log_set_flags(AV_LOG_SKIP_REPEATED);\n    parse_loglevel(argc, argv, options);\n\n#if CONFIG_AVDEVICE\n    avdevice_register_all();\n#endif\n    avformat_network_init();\n\n    show_banner(argc, argv, options);\n\n    /* parse options and open all input/output files */\n    ret = ffmpeg_parse_options(argc, argv);\n    if (ret < 0)\n        exit_program(1);\n\n    if (nb_output_files <= 0 && nb_input_files == 0) {\n        show_usage();\n        av_log(NULL, AV_LOG_WARNING, \"Use -h to get full help or, even better, run 'man %s'\\n\", program_name);\n        exit_program(1);\n    }\n\n    /* file converter / grab */\n    if (nb_output_files <= 0) {\n        av_log(NULL, AV_LOG_FATAL, \"At least one output file must be specified\\n\");\n        exit_program(1);\n    }\n\n    for (i = 0; i < nb_output_files; i++) {\n        if (strcmp(output_files[i]->format->name, \"rtp\"))\n            want_sdp = 0;\n    }\n\n    current_time = ti = get_benchmark_time_stamps();\n    if (transcode() < 0)\n        exit_program(1);\n    if (do_benchmark) {\n        int64_t utime, stime, rtime;\n        current_time = get_benchmark_time_stamps();\n        utime = current_time.user_usec - ti.user_usec;\n        stime = current_time.sys_usec  - ti.sys_usec;\n        rtime = current_time.real_usec - ti.real_usec;\n        av_log(NULL, AV_LOG_INFO,\n               \"bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\\n\",\n               utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);\n    }\n    av_log(NULL, AV_LOG_DEBUG, \"%\"PRIu64\" frames successfully decoded, %\"PRIu64\" decoding errors\\n\",\n           decode_error_stat[0], decode_error_stat[1]);\n    if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])\n        exit_program(69);\n\n    exit_program(received_nb_signals ? 255 : main_return_code);\n    return main_return_code;\n}\n"
  },
  {
    "path": "src/fftools/ffmpeg.h",
    "content": "/*\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFTOOLS_FFMPEG_H\n#define FFTOOLS_FFMPEG_H\n\n#include \"config.h\"\n\n#include <stdint.h>\n#include <stdio.h>\n#include <signal.h>\n\n#include \"cmdutils.h\"\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/avio.h\"\n\n#include \"libavcodec/avcodec.h\"\n#include \"libavcodec/bsf.h\"\n\n#include \"libavfilter/avfilter.h\"\n\n#include \"libavutil/avutil.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/eval.h\"\n#include \"libavutil/fifo.h\"\n#include \"libavutil/hwcontext.h\"\n#include \"libavutil/pixfmt.h\"\n#include \"libavutil/rational.h\"\n#include \"libavutil/thread.h\"\n#include \"libavutil/threadmessage.h\"\n\n#include \"libswresample/swresample.h\"\n\nenum VideoSyncMethod {\n    VSYNC_AUTO = -1,\n    VSYNC_PASSTHROUGH,\n    VSYNC_CFR,\n    VSYNC_VFR,\n    VSYNC_VSCFR,\n    VSYNC_DROP,\n};\n\n#define MAX_STREAMS 1024    /* arbitrary sanity check value */\n\nenum HWAccelID {\n    HWACCEL_NONE = 0,\n    HWACCEL_AUTO,\n    HWACCEL_GENERIC,\n};\n\ntypedef struct HWDevice {\n    const char *name;\n    enum AVHWDeviceType type;\n    AVBufferRef *device_ref;\n} HWDevice;\n\n/* select an input stream for an output stream */\ntypedef struct StreamMap {\n    int disabled;           /* 1 is this mapping is disabled by a negative map */\n    int file_index;\n    int stream_index;\n    int sync_file_index;\n    int sync_stream_index;\n    char *linklabel;       /* name of an output link, for mapping lavfi outputs */\n} StreamMap;\n\ntypedef struct {\n    int  file_idx,  stream_idx,  channel_idx; // input\n    int ofile_idx, ostream_idx;               // output\n} AudioChannelMap;\n\ntypedef struct OptionsContext {\n    OptionGroup *g;\n\n    /* input/output options */\n    int64_t start_time;\n    int64_t start_time_eof;\n    int seek_timestamp;\n    const char *format;\n\n    SpecifierOpt *codec_names;\n    int        nb_codec_names;\n    SpecifierOpt *audio_ch_layouts;\n    int        nb_audio_ch_layouts;\n    SpecifierOpt *audio_channels;\n    int        nb_audio_channels;\n    SpecifierOpt *audio_sample_rate;\n    int        nb_audio_sample_rate;\n    SpecifierOpt *frame_rates;\n    int        nb_frame_rates;\n    SpecifierOpt *max_frame_rates;\n    int        nb_max_frame_rates;\n    SpecifierOpt *frame_sizes;\n    int        nb_frame_sizes;\n    SpecifierOpt *frame_pix_fmts;\n    int        nb_frame_pix_fmts;\n\n    /* input options */\n    int64_t input_ts_offset;\n    int loop;\n    int rate_emu;\n    float readrate;\n    int accurate_seek;\n    int thread_queue_size;\n    int input_sync_ref;\n\n    SpecifierOpt *ts_scale;\n    int        nb_ts_scale;\n    SpecifierOpt *dump_attachment;\n    int        nb_dump_attachment;\n    SpecifierOpt *hwaccels;\n    int        nb_hwaccels;\n    SpecifierOpt *hwaccel_devices;\n    int        nb_hwaccel_devices;\n    SpecifierOpt *hwaccel_output_formats;\n    int        nb_hwaccel_output_formats;\n    SpecifierOpt *autorotate;\n    int        nb_autorotate;\n\n    /* output options */\n    StreamMap *stream_maps;\n    int     nb_stream_maps;\n    AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */\n    int           nb_audio_channel_maps; /* number of (valid) -map_channel settings */\n    int metadata_global_manual;\n    int metadata_streams_manual;\n    int metadata_chapters_manual;\n    const char **attachments;\n    int       nb_attachments;\n\n    int chapters_input_file;\n\n    int64_t recording_time;\n    int64_t stop_time;\n    uint64_t limit_filesize;\n    float mux_preload;\n    float mux_max_delay;\n    int shortest;\n    int bitexact;\n\n    int video_disable;\n    int audio_disable;\n    int subtitle_disable;\n    int data_disable;\n\n    /* indexed by output file stream index */\n    int   *streamid_map;\n    int nb_streamid_map;\n\n    SpecifierOpt *metadata;\n    int        nb_metadata;\n    SpecifierOpt *max_frames;\n    int        nb_max_frames;\n    SpecifierOpt *bitstream_filters;\n    int        nb_bitstream_filters;\n    SpecifierOpt *codec_tags;\n    int        nb_codec_tags;\n    SpecifierOpt *sample_fmts;\n    int        nb_sample_fmts;\n    SpecifierOpt *qscale;\n    int        nb_qscale;\n    SpecifierOpt *forced_key_frames;\n    int        nb_forced_key_frames;\n    SpecifierOpt *fps_mode;\n    int        nb_fps_mode;\n    SpecifierOpt *force_fps;\n    int        nb_force_fps;\n    SpecifierOpt *frame_aspect_ratios;\n    int        nb_frame_aspect_ratios;\n    SpecifierOpt *rc_overrides;\n    int        nb_rc_overrides;\n    SpecifierOpt *intra_matrices;\n    int        nb_intra_matrices;\n    SpecifierOpt *inter_matrices;\n    int        nb_inter_matrices;\n    SpecifierOpt *chroma_intra_matrices;\n    int        nb_chroma_intra_matrices;\n    SpecifierOpt *top_field_first;\n    int        nb_top_field_first;\n    SpecifierOpt *metadata_map;\n    int        nb_metadata_map;\n    SpecifierOpt *presets;\n    int        nb_presets;\n    SpecifierOpt *copy_initial_nonkeyframes;\n    int        nb_copy_initial_nonkeyframes;\n    SpecifierOpt *copy_prior_start;\n    int        nb_copy_prior_start;\n    SpecifierOpt *filters;\n    int        nb_filters;\n    SpecifierOpt *filter_scripts;\n    int        nb_filter_scripts;\n    SpecifierOpt *reinit_filters;\n    int        nb_reinit_filters;\n    SpecifierOpt *fix_sub_duration;\n    int        nb_fix_sub_duration;\n    SpecifierOpt *canvas_sizes;\n    int        nb_canvas_sizes;\n    SpecifierOpt *pass;\n    int        nb_pass;\n    SpecifierOpt *passlogfiles;\n    int        nb_passlogfiles;\n    SpecifierOpt *max_muxing_queue_size;\n    int        nb_max_muxing_queue_size;\n    SpecifierOpt *muxing_queue_data_threshold;\n    int        nb_muxing_queue_data_threshold;\n    SpecifierOpt *guess_layout_max;\n    int        nb_guess_layout_max;\n    SpecifierOpt *apad;\n    int        nb_apad;\n    SpecifierOpt *discard;\n    int        nb_discard;\n    SpecifierOpt *disposition;\n    int        nb_disposition;\n    SpecifierOpt *program;\n    int        nb_program;\n    SpecifierOpt *time_bases;\n    int        nb_time_bases;\n    SpecifierOpt *enc_time_bases;\n    int        nb_enc_time_bases;\n    SpecifierOpt *autoscale;\n    int        nb_autoscale;\n    SpecifierOpt *bits_per_raw_sample;\n    int        nb_bits_per_raw_sample;\n} OptionsContext;\n\ntypedef struct InputFilter {\n    AVFilterContext    *filter;\n    struct InputStream *ist;\n    struct FilterGraph *graph;\n    uint8_t            *name;\n    enum AVMediaType    type;   // AVMEDIA_TYPE_SUBTITLE for sub2video\n\n    AVFifo *frame_queue;\n\n    // parameters configured for this input\n    int format;\n\n    int width, height;\n    AVRational sample_aspect_ratio;\n\n    int sample_rate;\n    AVChannelLayout ch_layout;\n\n    AVBufferRef *hw_frames_ctx;\n    int32_t *displaymatrix;\n\n    int eof;\n} InputFilter;\n\ntypedef struct OutputFilter {\n    AVFilterContext     *filter;\n    struct OutputStream *ost;\n    struct FilterGraph  *graph;\n    uint8_t             *name;\n\n    /* temporary storage until stream maps are processed */\n    AVFilterInOut       *out_tmp;\n    enum AVMediaType     type;\n\n    /* desired output stream properties */\n    int width, height;\n    AVRational frame_rate;\n    int format;\n    int sample_rate;\n    AVChannelLayout ch_layout;\n\n    // those are only set if no format is specified and the encoder gives us multiple options\n    // They point directly to the relevant lists of the encoder.\n    const int *formats;\n    const AVChannelLayout *ch_layouts;\n    const int *sample_rates;\n} OutputFilter;\n\ntypedef struct FilterGraph {\n    int            index;\n    const char    *graph_desc;\n\n    AVFilterGraph *graph;\n    int reconfiguration;\n    // true when the filtergraph contains only meta filters\n    // that do not modify the frame data\n    int is_meta;\n\n    InputFilter   **inputs;\n    int          nb_inputs;\n    OutputFilter **outputs;\n    int         nb_outputs;\n} FilterGraph;\n\ntypedef struct InputStream {\n    int file_index;\n    AVStream *st;\n    int discard;             /* true if stream data should be discarded */\n    int user_set_discard;\n    int decoding_needed;     /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */\n#define DECODING_FOR_OST    1\n#define DECODING_FOR_FILTER 2\n    int processing_needed;   /* non zero if the packets must be processed */\n\n    AVCodecContext *dec_ctx;\n    const AVCodec *dec;\n    AVFrame *decoded_frame;\n    AVPacket *pkt;\n\n    int64_t       prev_pkt_pts;\n    int64_t       start;     /* time when read started */\n    /* predicted dts of the next packet read for this stream or (when there are\n     * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */\n    int64_t       next_dts;\n    int64_t first_dts;       ///< dts of the first packet read for this stream (in AV_TIME_BASE units)\n    int64_t       dts;       ///< dts of the last packet read for this stream (in AV_TIME_BASE units)\n\n    int64_t       next_pts;  ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)\n    int64_t       pts;       ///< current pts of the decoded frame  (in AV_TIME_BASE units)\n    int           wrap_correction_done;\n\n    int64_t filter_in_rescale_delta_last;\n\n    int64_t min_pts; /* pts with the smallest value in a current stream */\n    int64_t max_pts; /* pts with the higher value in a current stream */\n\n    // when forcing constant input framerate through -r,\n    // this contains the pts that will be given to the next decoded frame\n    int64_t cfr_next_pts;\n\n    int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */\n\n    double ts_scale;\n    int saw_first_ts;\n    AVDictionary *decoder_opts;\n    AVRational framerate;               /* framerate forced with -r */\n    int top_field_first;\n    int guess_layout_max;\n\n    int autorotate;\n\n    int fix_sub_duration;\n    struct { /* previous decoded subtitle and related variables */\n        int got_output;\n        int ret;\n        AVSubtitle subtitle;\n    } prev_sub;\n\n    struct sub2video {\n        int64_t last_pts;\n        int64_t end_pts;\n        AVFifo *sub_queue;    ///< queue of AVSubtitle* before filter init\n        AVFrame *frame;\n        int w, h;\n        unsigned int initialize; ///< marks if sub2video_update should force an initialization\n    } sub2video;\n\n    /* decoded data from this stream goes into all those filters\n     * currently video and audio only */\n    InputFilter **filters;\n    int        nb_filters;\n\n    int reinit_filters;\n\n    /* hwaccel options */\n    enum HWAccelID hwaccel_id;\n    enum AVHWDeviceType hwaccel_device_type;\n    char  *hwaccel_device;\n    enum AVPixelFormat hwaccel_output_format;\n\n    /* hwaccel context */\n    void  *hwaccel_ctx;\n    void (*hwaccel_uninit)(AVCodecContext *s);\n    int  (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);\n    enum AVPixelFormat hwaccel_pix_fmt;\n    enum AVPixelFormat hwaccel_retrieved_pix_fmt;\n\n    /* stats */\n    // combined size of all the packets read\n    uint64_t data_size;\n    /* number of packets successfully read for this stream */\n    uint64_t nb_packets;\n    // number of frames/samples retrieved from the decoder\n    uint64_t frames_decoded;\n    uint64_t samples_decoded;\n\n    int64_t *dts_buffer;\n    int nb_dts_buffer;\n\n    int got_output;\n} InputStream;\n\ntypedef struct InputFile {\n    AVFormatContext *ctx;\n    int eof_reached;      /* true if eof reached */\n    int eagain;           /* true if last read attempt returned EAGAIN */\n    int ist_index;        /* index of first stream in input_streams */\n    int loop;             /* set number of times input stream should be looped */\n    int64_t duration;     /* actual duration of the longest stream in a file\n                             at the moment when looping happens */\n    AVRational time_base; /* time base of the duration */\n    int64_t input_ts_offset;\n    int input_sync_ref;\n\n    int64_t ts_offset;\n    int64_t last_ts;\n    int64_t start_time;   /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */\n    int64_t recording_time;\n    int nb_streams;       /* number of stream that ffmpeg is aware of; may be different\n                             from ctx.nb_streams if new streams appear during av_read_frame() */\n    int nb_streams_warn;  /* number of streams that the user was warned of */\n    int rate_emu;\n    float readrate;\n    int accurate_seek;\n\n    AVPacket *pkt;\n\n#if HAVE_THREADS\n    AVThreadMessageQueue *in_thread_queue;\n    pthread_t thread;           /* thread reading from this file */\n    int non_blocking;           /* reading packets from the thread should not block */\n    int joined;                 /* the thread has been joined */\n    int thread_queue_size;      /* maximum number of queued packets */\n#endif\n} InputFile;\n\nenum forced_keyframes_const {\n    FKF_N,\n    FKF_N_FORCED,\n    FKF_PREV_FORCED_N,\n    FKF_PREV_FORCED_T,\n    FKF_T,\n    FKF_NB\n};\n\n#define ABORT_ON_FLAG_EMPTY_OUTPUT        (1 <<  0)\n#define ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM (1 <<  1)\n\nextern const char *const forced_keyframes_const_names[];\n\ntypedef enum {\n    ENCODER_FINISHED = 1,\n    MUXER_FINISHED = 2,\n} OSTFinished ;\n\ntypedef struct OutputStream {\n    int file_index;          /* file index */\n    int index;               /* stream index in the output file */\n    int source_index;        /* InputStream index */\n    AVStream *st;            /* stream in the output file */\n    int encoding_needed;     /* true if encoding needed for this stream */\n    int64_t frame_number;\n    /* input pts and corresponding output pts\n       for A/V sync */\n    struct InputStream *sync_ist; /* input stream to sync against */\n    int64_t sync_opts;       /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number\n    /* pts of the first frame encoded for this stream, used for limiting\n     * recording time */\n    int64_t first_pts;\n    /* dts of the last packet sent to the muxer */\n    int64_t last_mux_dts;\n    // the timebase of the packets sent to the muxer\n    AVRational mux_timebase;\n    AVRational enc_timebase;\n\n    AVBSFContext            *bsf_ctx;\n\n    AVCodecContext *enc_ctx;\n    AVCodecParameters *ref_par; /* associated input codec parameters with encoders options applied */\n    const AVCodec *enc;\n    int64_t max_frames;\n    AVFrame *filtered_frame;\n    AVFrame *last_frame;\n    AVPacket *pkt;\n    int64_t last_dropped;\n    int64_t last_nb0_frames[3];\n\n    void  *hwaccel_ctx;\n\n    /* video only */\n    AVRational frame_rate;\n    AVRational max_frame_rate;\n    enum VideoSyncMethod vsync_method;\n    int is_cfr;\n    const char *fps_mode;\n    int force_fps;\n    int top_field_first;\n    int rotate_overridden;\n    int autoscale;\n    int bits_per_raw_sample;\n    double rotate_override_value;\n\n    AVRational frame_aspect_ratio;\n\n    /* forced key frames */\n    int64_t forced_kf_ref_pts;\n    int64_t *forced_kf_pts;\n    int forced_kf_count;\n    int forced_kf_index;\n    char *forced_keyframes;\n    AVExpr *forced_keyframes_pexpr;\n    double forced_keyframes_expr_const_values[FKF_NB];\n    int dropped_keyframe;\n\n    /* audio only */\n    int *audio_channels_map;             /* list of the channels id to pick from the source stream */\n    int audio_channels_mapped;           /* number of channels in audio_channels_map */\n\n    char *logfile_prefix;\n    FILE *logfile;\n\n    OutputFilter *filter;\n    char *avfilter;\n    char *filters;         ///< filtergraph associated to the -filter option\n    char *filters_script;  ///< filtergraph script associated to the -filter_script option\n\n    AVDictionary *encoder_opts;\n    AVDictionary *sws_dict;\n    AVDictionary *swr_opts;\n    char *apad;\n    OSTFinished finished;        /* no more packets should be written for this stream */\n    int unavailable;                     /* true if the steram is unavailable (possibly temporarily) */\n    int stream_copy;\n\n    // init_output_stream() has been called for this stream\n    // The encoder and the bitstream filters have been initialized and the stream\n    // parameters are set in the AVStream.\n    int initialized;\n\n    int inputs_done;\n\n    const char *attachment_filename;\n    int streamcopy_started;\n    int copy_initial_nonkeyframes;\n    int copy_prior_start;\n    char *disposition;\n\n    int keep_pix_fmt;\n\n    /* stats */\n    // combined size of all the packets written\n    uint64_t data_size;\n    // number of packets send to the muxer\n    uint64_t packets_written;\n    // number of frames/samples sent to the encoder\n    uint64_t frames_encoded;\n    uint64_t samples_encoded;\n    // number of packets received from the encoder\n    uint64_t packets_encoded;\n\n    /* packet quality factor */\n    int quality;\n\n    int max_muxing_queue_size;\n\n    /* the packets are buffered here until the muxer is ready to be initialized */\n    AVFifo *muxing_queue;\n\n    /*\n     * The size of the AVPackets' buffers in queue.\n     * Updated when a packet is either pushed or pulled from the queue.\n     */\n    size_t muxing_queue_data_size;\n\n    /* Threshold after which max_muxing_queue_size will be in effect */\n    size_t muxing_queue_data_threshold;\n\n    /* packet picture type */\n    int pict_type;\n\n    /* frame encode sum of squared error values */\n    int64_t error[4];\n} OutputStream;\n\ntypedef struct OutputFile {\n    int index;\n\n    const AVOutputFormat *format;\n\n    AVFormatContext *ctx;\n    AVDictionary *opts;\n    int ost_index;       /* index of the first stream in output_streams */\n    int64_t recording_time;  ///< desired length of the resulting file in microseconds == AV_TIME_BASE units\n    int64_t start_time;      ///< start time in microseconds == AV_TIME_BASE units\n    uint64_t limit_filesize; /* filesize limit expressed in bytes */\n\n    int shortest;\n\n    int header_written;\n} OutputFile;\n\nextern InputStream **input_streams;\nextern int        nb_input_streams;\nextern InputFile   **input_files;\nextern int        nb_input_files;\n\nextern OutputStream **output_streams;\nextern int         nb_output_streams;\nextern OutputFile   **output_files;\nextern int         nb_output_files;\n\nextern FilterGraph **filtergraphs;\nextern int        nb_filtergraphs;\n\nextern char *vstats_filename;\nextern char *sdp_filename;\n\nextern float audio_drift_threshold;\nextern float dts_delta_threshold;\nextern float dts_error_threshold;\n\nextern int audio_volume;\nextern int audio_sync_method;\nextern enum VideoSyncMethod video_sync_method;\nextern float frame_drop_threshold;\nextern int do_benchmark;\nextern int do_benchmark_all;\nextern int do_deinterlace;\nextern int do_hex_dump;\nextern int do_pkt_dump;\nextern int copy_ts;\nextern int start_at_zero;\nextern int copy_tb;\nextern int debug_ts;\nextern int exit_on_error;\nextern int abort_on_flags;\nextern int print_stats;\nextern int64_t stats_period;\nextern int qp_hist;\nextern int stdin_interaction;\nextern int frame_bits_per_raw_sample;\nextern AVIOContext *progress_avio;\nextern float max_error_rate;\n\nextern char *filter_nbthreads;\nextern int filter_complex_nbthreads;\nextern int vstats_version;\nextern int auto_conversion_filters;\n\nextern const AVIOInterruptCB int_cb;\n\nextern const OptionDef options[];\n#if CONFIG_QSV\nextern char *qsv_device;\n#endif\nextern HWDevice *filter_hw_device;\n\nextern int want_sdp;\nextern unsigned nb_output_dumped;\nextern int main_return_code;\n\n\nvoid term_init(void);\nvoid term_exit(void);\n\nvoid show_usage(void);\n\nvoid remove_avoptions(AVDictionary **a, AVDictionary *b);\nvoid assert_avoptions(AVDictionary *m);\n\nint guess_input_channel_layout(InputStream *ist);\n\nint configure_filtergraph(FilterGraph *fg);\nvoid check_filter_outputs(void);\nint filtergraph_is_simple(FilterGraph *fg);\nint init_simple_filtergraph(InputStream *ist, OutputStream *ost);\nint init_complex_filtergraph(FilterGraph *fg);\n\nvoid sub2video_update(InputStream *ist, int64_t heartbeat_pts, AVSubtitle *sub);\n\nint ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);\n\nint ffmpeg_parse_options(int argc, char **argv);\n\nint videotoolbox_init(AVCodecContext *s);\nint qsv_init(AVCodecContext *s);\n\nHWDevice *hw_device_get_by_name(const char *name);\nint hw_device_init_from_string(const char *arg, HWDevice **dev);\nvoid hw_device_free_all(void);\n\nint hw_device_setup_for_decode(InputStream *ist);\nint hw_device_setup_for_encode(OutputStream *ost);\nint hw_device_setup_for_filter(FilterGraph *fg);\n\nint hwaccel_decode_init(AVCodecContext *avctx);\n\n/* open the muxer when all the streams are initialized */\nint of_check_init(OutputFile *of);\nint of_write_trailer(OutputFile *of);\nvoid of_close(OutputFile **pof);\n\nvoid of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost,\n                     int unqueue);\n\n#endif /* FFTOOLS_FFMPEG_H */\n"
  },
  {
    "path": "src/fftools/ffmpeg_filter.c",
    "content": "/*\n * ffmpeg filter configuration\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <stdint.h>\n\n#include \"ffmpeg.h\"\n\n#include \"libavfilter/avfilter.h\"\n#include \"libavfilter/buffersink.h\"\n#include \"libavfilter/buffersrc.h\"\n\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/display.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/pixfmt.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/samplefmt.h\"\n\n// FIXME: YUV420P etc. are actually supported with full color range,\n// yet the latter information isn't available here.\nstatic const enum AVPixelFormat *get_compliance_normal_pix_fmts(const AVCodec *codec, const enum AVPixelFormat default_formats[])\n{\n    static const enum AVPixelFormat mjpeg_formats[] =\n        { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,\n          AV_PIX_FMT_NONE };\n\n    if (!strcmp(codec->name, \"mjpeg\")) {\n        return mjpeg_formats;\n    } else {\n        return default_formats;\n    }\n}\n\nstatic enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx,\n                                    const AVCodec *codec, enum AVPixelFormat target)\n{\n    if (codec && codec->pix_fmts) {\n        const enum AVPixelFormat *p = codec->pix_fmts;\n        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);\n        //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented\n        int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;\n        enum AVPixelFormat best= AV_PIX_FMT_NONE;\n\n        if (enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {\n            p = get_compliance_normal_pix_fmts(codec, p);\n        }\n        for (; *p != AV_PIX_FMT_NONE; p++) {\n            best = av_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);\n            if (*p == target)\n                break;\n        }\n        if (*p == AV_PIX_FMT_NONE) {\n            if (target != AV_PIX_FMT_NONE)\n                av_log(NULL, AV_LOG_WARNING,\n                       \"Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\\n\",\n                       av_get_pix_fmt_name(target),\n                       codec->name,\n                       av_get_pix_fmt_name(best));\n            return best;\n        }\n    }\n    return target;\n}\n\n/* May return NULL (no pixel format found), a static string or a string\n * backed by the bprint. Nothing has been written to the AVBPrint in case\n * NULL is returned. The AVBPrint provided should be clean. */\nstatic const char *choose_pix_fmts(OutputFilter *ofilter, AVBPrint *bprint)\n{\n    OutputStream *ost = ofilter->ost;\n    const AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, \"strict\", NULL, 0);\n    if (strict_dict)\n        // used by choose_pixel_fmt() and below\n        av_opt_set(ost->enc_ctx, \"strict\", strict_dict->value, 0);\n\n     if (ost->keep_pix_fmt) {\n        avfilter_graph_set_auto_convert(ofilter->graph->graph,\n                                            AVFILTER_AUTO_CONVERT_NONE);\n        if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE)\n            return NULL;\n        return av_get_pix_fmt_name(ost->enc_ctx->pix_fmt);\n    }\n    if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {\n        return av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt));\n    } else if (ost->enc && ost->enc->pix_fmts) {\n        const enum AVPixelFormat *p;\n\n        p = ost->enc->pix_fmts;\n        if (ost->enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {\n            p = get_compliance_normal_pix_fmts(ost->enc, p);\n        }\n\n        for (; *p != AV_PIX_FMT_NONE; p++) {\n            const char *name = av_get_pix_fmt_name(*p);\n            av_bprintf(bprint, \"%s%c\", name, p[1] == AV_PIX_FMT_NONE ? '\\0' : '|');\n        }\n        if (!av_bprint_is_complete(bprint))\n            exit_program(1);\n        return bprint->str;\n    } else\n        return NULL;\n}\n\n/* Define a function for appending a list of allowed formats\n * to an AVBPrint. If nonempty, the list will have a header. */\n#define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \\\nstatic void choose_ ## name (OutputFilter *ofilter, AVBPrint *bprint)          \\\n{                                                                              \\\n    if (ofilter->var == none && !ofilter->supported_list)                      \\\n        return;                                                                \\\n    av_bprintf(bprint, #name \"=\");                                             \\\n    if (ofilter->var != none) {                                                \\\n        av_bprintf(bprint, printf_format, get_name(ofilter->var));             \\\n    } else {                                                                   \\\n        const type *p;                                                         \\\n                                                                               \\\n        for (p = ofilter->supported_list; *p != none; p++) {                   \\\n            av_bprintf(bprint, printf_format \"|\", get_name(*p));               \\\n        }                                                                      \\\n        if (bprint->len > 0)                                                   \\\n            bprint->str[--bprint->len] = '\\0';                                 \\\n    }                                                                          \\\n    av_bprint_chars(bprint, ':', 1);                                           \\\n}\n\n//DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE,\n//                  GET_PIX_FMT_NAME)\n\nDEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats,\n                  AV_SAMPLE_FMT_NONE, \"%s\", av_get_sample_fmt_name)\n\nDEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0,\n                  \"%d\", )\n\nstatic void choose_channel_layouts(OutputFilter *ofilter, AVBPrint *bprint)\n{\n    if (av_channel_layout_check(&ofilter->ch_layout)) {\n        av_bprintf(bprint, \"channel_layouts=\");\n        av_channel_layout_describe_bprint(&ofilter->ch_layout, bprint);\n    } else if (ofilter->ch_layouts) {\n        const AVChannelLayout *p;\n\n        av_bprintf(bprint, \"channel_layouts=\");\n        for (p = ofilter->ch_layouts; p->nb_channels; p++) {\n            av_channel_layout_describe_bprint(p, bprint);\n            av_bprintf(bprint, \"|\");\n        }\n        if (bprint->len > 0)\n            bprint->str[--bprint->len] = '\\0';\n    } else\n        return;\n    av_bprint_chars(bprint, ':', 1);\n}\n\nint init_simple_filtergraph(InputStream *ist, OutputStream *ost)\n{\n    FilterGraph *fg = av_mallocz(sizeof(*fg));\n    OutputFilter *ofilter;\n    InputFilter  *ifilter;\n\n    if (!fg)\n        exit_program(1);\n    fg->index = nb_filtergraphs;\n\n    ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);\n    ofilter->ost    = ost;\n    ofilter->graph  = fg;\n    ofilter->format = -1;\n\n    ost->filter = ofilter;\n\n    ifilter = ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);\n    ifilter->ist    = ist;\n    ifilter->graph  = fg;\n    ifilter->format = -1;\n\n    ifilter->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);\n    if (!ifilter->frame_queue)\n        exit_program(1);\n\n    GROW_ARRAY(ist->filters, ist->nb_filters);\n    ist->filters[ist->nb_filters - 1] = ifilter;\n\n    GROW_ARRAY(filtergraphs, nb_filtergraphs);\n    filtergraphs[nb_filtergraphs - 1] = fg;\n\n    return 0;\n}\n\nstatic char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)\n{\n    AVFilterContext *ctx = inout->filter_ctx;\n    AVFilterPad *pads = in ? ctx->input_pads  : ctx->output_pads;\n    int       nb_pads = in ? ctx->nb_inputs   : ctx->nb_outputs;\n    char *res;\n\n    if (nb_pads > 1)\n        res = av_strdup(ctx->filter->name);\n    else\n        res = av_asprintf(\"%s:%s\", ctx->filter->name,\n                          avfilter_pad_get_name(pads, inout->pad_idx));\n    if (!res)\n        exit_program(1);\n    return res;\n}\n\nstatic void init_input_filter(FilterGraph *fg, AVFilterInOut *in)\n{\n    InputStream *ist = NULL;\n    enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);\n    InputFilter *ifilter;\n    int i;\n\n    // TODO: support other filter types\n    if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {\n        av_log(NULL, AV_LOG_FATAL, \"Only video and audio filters supported \"\n               \"currently.\\n\");\n        exit_program(1);\n    }\n\n    if (in->name) {\n        AVFormatContext *s;\n        AVStream       *st = NULL;\n        char *p;\n        int file_idx = strtol(in->name, &p, 0);\n\n        if (file_idx < 0 || file_idx >= nb_input_files) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid file index %d in filtergraph description %s.\\n\",\n                   file_idx, fg->graph_desc);\n            exit_program(1);\n        }\n        s = input_files[file_idx]->ctx;\n\n        for (i = 0; i < s->nb_streams; i++) {\n            enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;\n            if (stream_type != type &&\n                !(stream_type == AVMEDIA_TYPE_SUBTITLE &&\n                  type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))\n                continue;\n            if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {\n                st = s->streams[i];\n                break;\n            }\n        }\n        if (!st) {\n            av_log(NULL, AV_LOG_FATAL, \"Stream specifier '%s' in filtergraph description %s \"\n                   \"matches no streams.\\n\", p, fg->graph_desc);\n            exit_program(1);\n        }\n        ist = input_streams[input_files[file_idx]->ist_index + st->index];\n        if (ist->user_set_discard == AVDISCARD_ALL) {\n            av_log(NULL, AV_LOG_FATAL, \"Stream specifier '%s' in filtergraph description %s \"\n                   \"matches a disabled input stream.\\n\", p, fg->graph_desc);\n            exit_program(1);\n        }\n    } else {\n        /* find the first unused stream of corresponding type */\n        for (i = 0; i < nb_input_streams; i++) {\n            ist = input_streams[i];\n            if (ist->user_set_discard == AVDISCARD_ALL)\n                continue;\n            if (ist->dec_ctx->codec_type == type && ist->discard)\n                break;\n        }\n        if (i == nb_input_streams) {\n            av_log(NULL, AV_LOG_FATAL, \"Cannot find a matching stream for \"\n                   \"unlabeled input pad %d on filter %s\\n\", in->pad_idx,\n                   in->filter_ctx->name);\n            exit_program(1);\n        }\n    }\n    av_assert0(ist);\n\n    ist->discard         = 0;\n    ist->decoding_needed |= DECODING_FOR_FILTER;\n    ist->processing_needed = 1;\n    ist->st->discard = AVDISCARD_NONE;\n\n    ifilter = ALLOC_ARRAY_ELEM(fg->inputs, fg->nb_inputs);\n    ifilter->ist    = ist;\n    ifilter->graph  = fg;\n    ifilter->format = -1;\n    ifilter->type   = ist->st->codecpar->codec_type;\n    ifilter->name   = describe_filter_link(fg, in, 1);\n\n    ifilter->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);\n    if (!ifilter->frame_queue)\n        exit_program(1);\n\n    GROW_ARRAY(ist->filters, ist->nb_filters);\n    ist->filters[ist->nb_filters - 1] = ifilter;\n}\n\nint init_complex_filtergraph(FilterGraph *fg)\n{\n    AVFilterInOut *inputs, *outputs, *cur;\n    AVFilterGraph *graph;\n    int ret = 0;\n\n    /* this graph is only used for determining the kinds of inputs\n     * and outputs we have, and is discarded on exit from this function */\n    graph = avfilter_graph_alloc();\n    if (!graph)\n        return AVERROR(ENOMEM);\n    graph->nb_threads = 1;\n\n    ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs);\n    if (ret < 0)\n        goto fail;\n\n    for (cur = inputs; cur; cur = cur->next)\n        init_input_filter(fg, cur);\n\n    for (cur = outputs; cur;) {\n        OutputFilter *const ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);\n\n        ofilter->graph   = fg;\n        ofilter->out_tmp = cur;\n        ofilter->type    = avfilter_pad_get_type(cur->filter_ctx->output_pads,\n                                                                         cur->pad_idx);\n        ofilter->name    = describe_filter_link(fg, cur, 0);\n        cur = cur->next;\n        ofilter->out_tmp->next = NULL;\n    }\n\nfail:\n    avfilter_inout_free(&inputs);\n    avfilter_graph_free(&graph);\n    return ret;\n}\n\nstatic int insert_trim(int64_t start_time, int64_t duration,\n                       AVFilterContext **last_filter, int *pad_idx,\n                       const char *filter_name)\n{\n    AVFilterGraph *graph = (*last_filter)->graph;\n    AVFilterContext *ctx;\n    const AVFilter *trim;\n    enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);\n    const char *name = (type == AVMEDIA_TYPE_VIDEO) ? \"trim\" : \"atrim\";\n    int ret = 0;\n\n    if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)\n        return 0;\n\n    trim = avfilter_get_by_name(name);\n    if (!trim) {\n        av_log(NULL, AV_LOG_ERROR, \"%s filter not present, cannot limit \"\n               \"recording time.\\n\", name);\n        return AVERROR_FILTER_NOT_FOUND;\n    }\n\n    ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);\n    if (!ctx)\n        return AVERROR(ENOMEM);\n\n    if (duration != INT64_MAX) {\n        ret = av_opt_set_int(ctx, \"durationi\", duration,\n                                AV_OPT_SEARCH_CHILDREN);\n    }\n    if (ret >= 0 && start_time != AV_NOPTS_VALUE) {\n        ret = av_opt_set_int(ctx, \"starti\", start_time,\n                                AV_OPT_SEARCH_CHILDREN);\n    }\n    if (ret < 0) {\n        av_log(ctx, AV_LOG_ERROR, \"Error configuring the %s filter\", name);\n        return ret;\n    }\n\n    ret = avfilter_init_str(ctx, NULL);\n    if (ret < 0)\n        return ret;\n\n    ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);\n    if (ret < 0)\n        return ret;\n\n    *last_filter = ctx;\n    *pad_idx     = 0;\n    return 0;\n}\n\nstatic int insert_filter(AVFilterContext **last_filter, int *pad_idx,\n                         const char *filter_name, const char *args)\n{\n    AVFilterGraph *graph = (*last_filter)->graph;\n    AVFilterContext *ctx;\n    int ret;\n\n    ret = avfilter_graph_create_filter(&ctx,\n                                       avfilter_get_by_name(filter_name),\n                                       filter_name, args, NULL, graph);\n    if (ret < 0)\n        return ret;\n\n    ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);\n    if (ret < 0)\n        return ret;\n\n    *last_filter = ctx;\n    *pad_idx     = 0;\n    return 0;\n}\n\nstatic int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)\n{\n    OutputStream *ost = ofilter->ost;\n    OutputFile    *of = output_files[ost->file_index];\n    AVFilterContext *last_filter = out->filter_ctx;\n    AVBPrint bprint;\n    int pad_idx = out->pad_idx;\n    int ret;\n    const char *pix_fmts;\n    char name[255];\n\n    snprintf(name, sizeof(name), \"out_%d_%d\", ost->file_index, ost->index);\n    ret = avfilter_graph_create_filter(&ofilter->filter,\n                                       avfilter_get_by_name(\"buffersink\"),\n                                       name, NULL, NULL, fg->graph);\n\n    if (ret < 0)\n        return ret;\n\n    if ((ofilter->width || ofilter->height) && ofilter->ost->autoscale) {\n        char args[255];\n        AVFilterContext *filter;\n        const AVDictionaryEntry *e = NULL;\n\n        snprintf(args, sizeof(args), \"%d:%d\",\n                 ofilter->width, ofilter->height);\n\n        while ((e = av_dict_get(ost->sws_dict, \"\", e,\n                                AV_DICT_IGNORE_SUFFIX))) {\n            av_strlcatf(args, sizeof(args), \":%s=%s\", e->key, e->value);\n        }\n\n        snprintf(name, sizeof(name), \"scaler_out_%d_%d\",\n                 ost->file_index, ost->index);\n        if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name(\"scale\"),\n                                                name, args, NULL, fg->graph)) < 0)\n            return ret;\n        if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)\n            return ret;\n\n        last_filter = filter;\n        pad_idx = 0;\n    }\n\n    av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);\n    if ((pix_fmts = choose_pix_fmts(ofilter, &bprint))) {\n        AVFilterContext *filter;\n\n        ret = avfilter_graph_create_filter(&filter,\n                                           avfilter_get_by_name(\"format\"),\n                                           \"format\", pix_fmts, NULL, fg->graph);\n        av_bprint_finalize(&bprint, NULL);\n        if (ret < 0)\n            return ret;\n        if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)\n            return ret;\n\n        last_filter = filter;\n        pad_idx     = 0;\n    }\n\n    if (ost->frame_rate.num && 0) {\n        AVFilterContext *fps;\n        char args[255];\n\n        snprintf(args, sizeof(args), \"fps=%d/%d\", ost->frame_rate.num,\n                 ost->frame_rate.den);\n        snprintf(name, sizeof(name), \"fps_out_%d_%d\",\n                 ost->file_index, ost->index);\n        ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name(\"fps\"),\n                                           name, args, NULL, fg->graph);\n        if (ret < 0)\n            return ret;\n\n        ret = avfilter_link(last_filter, pad_idx, fps, 0);\n        if (ret < 0)\n            return ret;\n        last_filter = fps;\n        pad_idx = 0;\n    }\n\n    snprintf(name, sizeof(name), \"trim_out_%d_%d\",\n             ost->file_index, ost->index);\n    ret = insert_trim(of->start_time, of->recording_time,\n                      &last_filter, &pad_idx, name);\n    if (ret < 0)\n        return ret;\n\n\n    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)\n        return ret;\n\n    return 0;\n}\n\nstatic int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)\n{\n    OutputStream *ost = ofilter->ost;\n    OutputFile    *of = output_files[ost->file_index];\n    AVCodecContext *codec  = ost->enc_ctx;\n    AVFilterContext *last_filter = out->filter_ctx;\n    int pad_idx = out->pad_idx;\n    AVBPrint args;\n    char name[255];\n    int ret;\n\n    snprintf(name, sizeof(name), \"out_%d_%d\", ost->file_index, ost->index);\n    ret = avfilter_graph_create_filter(&ofilter->filter,\n                                       avfilter_get_by_name(\"abuffersink\"),\n                                       name, NULL, NULL, fg->graph);\n    if (ret < 0)\n        return ret;\n    if ((ret = av_opt_set_int(ofilter->filter, \"all_channel_counts\", 1, AV_OPT_SEARCH_CHILDREN)) < 0)\n        return ret;\n\n#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do {                 \\\n    AVFilterContext *filt_ctx;                                              \\\n                                                                            \\\n    av_log(NULL, AV_LOG_INFO, opt_name \" is forwarded to lavfi \"            \\\n           \"similarly to -af \" filter_name \"=%s.\\n\", arg);                  \\\n                                                                            \\\n    ret = avfilter_graph_create_filter(&filt_ctx,                           \\\n                                       avfilter_get_by_name(filter_name),   \\\n                                       filter_name, arg, NULL, fg->graph);  \\\n    if (ret < 0)                                                            \\\n        goto fail;                                                          \\\n                                                                            \\\n    ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0);                 \\\n    if (ret < 0)                                                            \\\n        goto fail;                                                          \\\n                                                                            \\\n    last_filter = filt_ctx;                                                 \\\n    pad_idx = 0;                                                            \\\n} while (0)\n    av_bprint_init(&args, 0, AV_BPRINT_SIZE_UNLIMITED);\n    if (ost->audio_channels_mapped) {\n        AVChannelLayout mapped_layout = { 0 };\n        int i;\n        av_channel_layout_default(&mapped_layout, ost->audio_channels_mapped);\n        av_channel_layout_describe_bprint(&mapped_layout, &args);\n        for (i = 0; i < ost->audio_channels_mapped; i++)\n            if (ost->audio_channels_map[i] != -1)\n                av_bprintf(&args, \"|c%d=c%d\", i, ost->audio_channels_map[i]);\n\n        AUTO_INSERT_FILTER(\"-map_channel\", \"pan\", args.str);\n        av_bprint_clear(&args);\n    }\n\n    if (codec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)\n        av_channel_layout_default(&codec->ch_layout, codec->ch_layout.nb_channels);\n\n    choose_sample_fmts(ofilter,     &args);\n    choose_sample_rates(ofilter,    &args);\n    choose_channel_layouts(ofilter, &args);\n    if (!av_bprint_is_complete(&args)) {\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n    if (args.len) {\n        AVFilterContext *format;\n\n        snprintf(name, sizeof(name), \"format_out_%d_%d\",\n                 ost->file_index, ost->index);\n        ret = avfilter_graph_create_filter(&format,\n                                           avfilter_get_by_name(\"aformat\"),\n                                           name, args.str, NULL, fg->graph);\n        if (ret < 0)\n            goto fail;\n\n        ret = avfilter_link(last_filter, pad_idx, format, 0);\n        if (ret < 0)\n            goto fail;\n\n        last_filter = format;\n        pad_idx = 0;\n    }\n\n    if (ost->apad && of->shortest) {\n        int i;\n\n        for (i=0; i<of->ctx->nb_streams; i++)\n            if (of->ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)\n                break;\n\n        if (i<of->ctx->nb_streams) {\n            AUTO_INSERT_FILTER(\"-apad\", \"apad\", ost->apad);\n        }\n    }\n\n    snprintf(name, sizeof(name), \"trim for output stream %d:%d\",\n             ost->file_index, ost->index);\n    ret = insert_trim(of->start_time, of->recording_time,\n                      &last_filter, &pad_idx, name);\n    if (ret < 0)\n        goto fail;\n\n    if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)\n        goto fail;\nfail:\n    av_bprint_finalize(&args, NULL);\n\n    return ret;\n}\n\nstatic int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter,\n                                   AVFilterInOut *out)\n{\n    if (!ofilter->ost) {\n        av_log(NULL, AV_LOG_FATAL, \"Filter %s has an unconnected output\\n\", ofilter->name);\n        exit_program(1);\n    }\n\n    switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {\n    case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);\n    case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);\n    default: av_assert0(0); return 0;\n    }\n}\n\nvoid check_filter_outputs(void)\n{\n    int i;\n    for (i = 0; i < nb_filtergraphs; i++) {\n        int n;\n        for (n = 0; n < filtergraphs[i]->nb_outputs; n++) {\n            OutputFilter *output = filtergraphs[i]->outputs[n];\n            if (!output->ost) {\n                av_log(NULL, AV_LOG_FATAL, \"Filter %s has an unconnected output\\n\", output->name);\n                exit_program(1);\n            }\n        }\n    }\n}\n\nstatic int sub2video_prepare(InputStream *ist, InputFilter *ifilter)\n{\n    AVFormatContext *avf = input_files[ist->file_index]->ctx;\n    int i, w, h;\n\n    /* Compute the size of the canvas for the subtitles stream.\n       If the subtitles codecpar has set a size, use it. Otherwise use the\n       maximum dimensions of the video streams in the same file. */\n    w = ifilter->width;\n    h = ifilter->height;\n    if (!(w && h)) {\n        for (i = 0; i < avf->nb_streams; i++) {\n            if (avf->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {\n                w = FFMAX(w, avf->streams[i]->codecpar->width);\n                h = FFMAX(h, avf->streams[i]->codecpar->height);\n            }\n        }\n        if (!(w && h)) {\n            w = FFMAX(w, 720);\n            h = FFMAX(h, 576);\n        }\n        av_log(avf, AV_LOG_INFO, \"sub2video: using %dx%d canvas\\n\", w, h);\n    }\n    ist->sub2video.w = ifilter->width  = w;\n    ist->sub2video.h = ifilter->height = h;\n\n    ifilter->width  = ist->dec_ctx->width  ? ist->dec_ctx->width  : ist->sub2video.w;\n    ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;\n\n    /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the\n       palettes for all rectangles are identical or compatible */\n    ifilter->format = AV_PIX_FMT_RGB32;\n\n    ist->sub2video.frame = av_frame_alloc();\n    if (!ist->sub2video.frame)\n        return AVERROR(ENOMEM);\n    ist->sub2video.last_pts = INT64_MIN;\n    ist->sub2video.end_pts  = INT64_MIN;\n\n    /* sub2video structure has been (re-)initialized.\n       Mark it as such so that the system will be\n       initialized with the first received heartbeat. */\n    ist->sub2video.initialize = 1;\n\n    return 0;\n}\n\nstatic int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,\n                                        AVFilterInOut *in)\n{\n    AVFilterContext *last_filter;\n    const AVFilter *buffer_filt = avfilter_get_by_name(\"buffer\");\n    const AVPixFmtDescriptor *desc;\n    InputStream *ist = ifilter->ist;\n    InputFile     *f = input_files[ist->file_index];\n    AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :\n                                         ist->st->time_base;\n    AVRational fr = ist->framerate;\n    AVRational sar;\n    AVBPrint args;\n    char name[255];\n    int ret, pad_idx = 0;\n    int64_t tsoffset = 0;\n    AVBufferSrcParameters *par = av_buffersrc_parameters_alloc();\n\n    if (!par)\n        return AVERROR(ENOMEM);\n    memset(par, 0, sizeof(*par));\n    par->format = AV_PIX_FMT_NONE;\n\n    if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {\n        av_log(NULL, AV_LOG_ERROR, \"Cannot connect video filter to audio input\\n\");\n        ret = AVERROR(EINVAL);\n        goto fail;\n    }\n\n    if (!fr.num)\n        fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);\n\n    if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {\n        ret = sub2video_prepare(ist, ifilter);\n        if (ret < 0)\n            goto fail;\n    }\n\n    sar = ifilter->sample_aspect_ratio;\n    if(!sar.den)\n        sar = (AVRational){0,1};\n    av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    av_bprintf(&args,\n             \"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:\"\n             \"pixel_aspect=%d/%d\",\n             ifilter->width, ifilter->height, ifilter->format,\n             tb.num, tb.den, sar.num, sar.den);\n    if (fr.num && fr.den)\n        av_bprintf(&args, \":frame_rate=%d/%d\", fr.num, fr.den);\n    snprintf(name, sizeof(name), \"graph %d input from stream %d:%d\", fg->index,\n             ist->file_index, ist->st->index);\n\n\n    if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,\n                                            args.str, NULL, fg->graph)) < 0)\n        goto fail;\n    par->hw_frames_ctx = ifilter->hw_frames_ctx;\n    ret = av_buffersrc_parameters_set(ifilter->filter, par);\n    if (ret < 0)\n        goto fail;\n    av_freep(&par);\n    last_filter = ifilter->filter;\n\n    desc = av_pix_fmt_desc_get(ifilter->format);\n    av_assert0(desc);\n\n    // TODO: insert hwaccel enabled filters like transpose_vaapi into the graph\n    if (ist->autorotate && !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {\n        int32_t *displaymatrix = ifilter->displaymatrix;\n        double theta;\n\n        if (!displaymatrix)\n            displaymatrix = (int32_t *)av_stream_get_side_data(ist->st, AV_PKT_DATA_DISPLAYMATRIX, NULL);\n        theta = get_rotation(displaymatrix);\n\n        if (fabs(theta - 90) < 1.0) {\n            ret = insert_filter(&last_filter, &pad_idx, \"transpose\",\n                                displaymatrix[3] > 0 ? \"cclock_flip\" : \"clock\");\n        } else if (fabs(theta - 180) < 1.0) {\n            if (displaymatrix[0] < 0) {\n                ret = insert_filter(&last_filter, &pad_idx, \"hflip\", NULL);\n                if (ret < 0)\n                    return ret;\n            }\n            if (displaymatrix[4] < 0) {\n                ret = insert_filter(&last_filter, &pad_idx, \"vflip\", NULL);\n            }\n        } else if (fabs(theta - 270) < 1.0) {\n            ret = insert_filter(&last_filter, &pad_idx, \"transpose\",\n                                displaymatrix[3] < 0 ? \"clock_flip\" : \"cclock\");\n        } else if (fabs(theta) > 1.0) {\n            char rotate_buf[64];\n            snprintf(rotate_buf, sizeof(rotate_buf), \"%f*PI/180\", theta);\n            ret = insert_filter(&last_filter, &pad_idx, \"rotate\", rotate_buf);\n        } else if (fabs(theta) < 1.0) {\n            if (displaymatrix && displaymatrix[4] < 0) {\n                ret = insert_filter(&last_filter, &pad_idx, \"vflip\", NULL);\n            }\n        }\n        if (ret < 0)\n            return ret;\n    }\n\n    snprintf(name, sizeof(name), \"trim_in_%d_%d\",\n             ist->file_index, ist->st->index);\n    if (copy_ts) {\n        tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;\n        if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)\n            tsoffset += f->ctx->start_time;\n    }\n    ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?\n                      AV_NOPTS_VALUE : tsoffset, f->recording_time,\n                      &last_filter, &pad_idx, name);\n    if (ret < 0)\n        return ret;\n\n    if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)\n        return ret;\n    return 0;\nfail:\n    av_freep(&par);\n\n    return ret;\n}\n\nstatic int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,\n                                        AVFilterInOut *in)\n{\n    AVFilterContext *last_filter;\n    const AVFilter *abuffer_filt = avfilter_get_by_name(\"abuffer\");\n    InputStream *ist = ifilter->ist;\n    InputFile     *f = input_files[ist->file_index];\n    AVBPrint args;\n    char name[255];\n    int ret, pad_idx = 0;\n    int64_t tsoffset = 0;\n\n    if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO) {\n        av_log(NULL, AV_LOG_ERROR, \"Cannot connect audio filter to non audio input\\n\");\n        return AVERROR(EINVAL);\n    }\n\n    av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    av_bprintf(&args, \"time_base=%d/%d:sample_rate=%d:sample_fmt=%s\",\n             1, ifilter->sample_rate,\n             ifilter->sample_rate,\n             av_get_sample_fmt_name(ifilter->format));\n    if (av_channel_layout_check(&ifilter->ch_layout) &&\n        ifilter->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {\n        av_bprintf(&args, \":channel_layout=\");\n        av_channel_layout_describe_bprint(&ifilter->ch_layout, &args);\n    } else\n        av_bprintf(&args, \":channels=%d\", ifilter->ch_layout.nb_channels);\n    snprintf(name, sizeof(name), \"graph_%d_in_%d_%d\", fg->index,\n             ist->file_index, ist->st->index);\n\n    if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,\n                                            name, args.str, NULL,\n                                            fg->graph)) < 0)\n        return ret;\n    last_filter = ifilter->filter;\n\n#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do {                 \\\n    AVFilterContext *filt_ctx;                                              \\\n                                                                            \\\n    av_log(NULL, AV_LOG_INFO, opt_name \" is forwarded to lavfi \"            \\\n           \"similarly to -af \" filter_name \"=%s.\\n\", arg);                  \\\n                                                                            \\\n    snprintf(name, sizeof(name), \"graph_%d_%s_in_%d_%d\",      \\\n                fg->index, filter_name, ist->file_index, ist->st->index);   \\\n    ret = avfilter_graph_create_filter(&filt_ctx,                           \\\n                                       avfilter_get_by_name(filter_name),   \\\n                                       name, arg, NULL, fg->graph);         \\\n    if (ret < 0)                                                            \\\n        return ret;                                                         \\\n                                                                            \\\n    ret = avfilter_link(last_filter, 0, filt_ctx, 0);                       \\\n    if (ret < 0)                                                            \\\n        return ret;                                                         \\\n                                                                            \\\n    last_filter = filt_ctx;                                                 \\\n} while (0)\n\n    if (audio_sync_method > 0) {\n        char args[256] = {0};\n\n        av_strlcatf(args, sizeof(args), \"async=%d\", audio_sync_method);\n        if (audio_drift_threshold != 0.1)\n            av_strlcatf(args, sizeof(args), \":min_hard_comp=%f\", audio_drift_threshold);\n        if (!fg->reconfiguration)\n            av_strlcatf(args, sizeof(args), \":first_pts=0\");\n        AUTO_INSERT_FILTER_INPUT(\"-async\", \"aresample\", args);\n    }\n\n//     if (ost->audio_channels_mapped) {\n//         int i;\n//         AVBPrint pan_buf;\n//         av_bprint_init(&pan_buf, 256, 8192);\n//         av_bprintf(&pan_buf, \"0x%\"PRIx64,\n//                    av_get_default_channel_layout(ost->audio_channels_mapped));\n//         for (i = 0; i < ost->audio_channels_mapped; i++)\n//             if (ost->audio_channels_map[i] != -1)\n//                 av_bprintf(&pan_buf, \":c%d=c%d\", i, ost->audio_channels_map[i]);\n//         AUTO_INSERT_FILTER_INPUT(\"-map_channel\", \"pan\", pan_buf.str);\n//         av_bprint_finalize(&pan_buf, NULL);\n//     }\n\n    if (audio_volume != 256) {\n        char args[256];\n\n        av_log(NULL, AV_LOG_WARNING, \"-vol has been deprecated. Use the volume \"\n               \"audio filter instead.\\n\");\n\n        snprintf(args, sizeof(args), \"%f\", audio_volume / 256.);\n        AUTO_INSERT_FILTER_INPUT(\"-vol\", \"volume\", args);\n    }\n\n    snprintf(name, sizeof(name), \"trim for input stream %d:%d\",\n             ist->file_index, ist->st->index);\n    if (copy_ts) {\n        tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;\n        if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)\n            tsoffset += f->ctx->start_time;\n    }\n    ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?\n                      AV_NOPTS_VALUE : tsoffset, f->recording_time,\n                      &last_filter, &pad_idx, name);\n    if (ret < 0)\n        return ret;\n\n    if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)\n        return ret;\n\n    return 0;\n}\n\nstatic int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,\n                                  AVFilterInOut *in)\n{\n    if (!ifilter->ist->dec) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"No decoder for stream #%d:%d, filtering impossible\\n\",\n               ifilter->ist->file_index, ifilter->ist->st->index);\n        return AVERROR_DECODER_NOT_FOUND;\n    }\n    switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {\n    case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);\n    case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);\n    default: av_assert0(0); return 0;\n    }\n}\n\nstatic void cleanup_filtergraph(FilterGraph *fg)\n{\n    int i;\n    for (i = 0; i < fg->nb_outputs; i++)\n        fg->outputs[i]->filter = (AVFilterContext *)NULL;\n    for (i = 0; i < fg->nb_inputs; i++)\n        fg->inputs[i]->filter = (AVFilterContext *)NULL;\n    avfilter_graph_free(&fg->graph);\n}\n\nstatic int filter_is_buffersrc(const AVFilterContext *f)\n{\n    return f->nb_inputs == 0 &&\n           (!strcmp(f->filter->name, \"buffer\") ||\n            !strcmp(f->filter->name, \"abuffer\"));\n}\n\nstatic int graph_is_meta(AVFilterGraph *graph)\n{\n    for (unsigned i = 0; i < graph->nb_filters; i++) {\n        const AVFilterContext *f = graph->filters[i];\n\n        /* in addition to filters flagged as meta, also\n         * disregard sinks and buffersources (but not other sources,\n         * since they introduce data we are not aware of)\n         */\n        if (!((f->filter->flags & AVFILTER_FLAG_METADATA_ONLY) ||\n              f->nb_outputs == 0                               ||\n              filter_is_buffersrc(f)))\n            return 0;\n    }\n    return 1;\n}\n\nint configure_filtergraph(FilterGraph *fg)\n{\n    AVFilterInOut *inputs, *outputs, *cur;\n    int ret, i, simple = filtergraph_is_simple(fg);\n    const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :\n                                      fg->graph_desc;\n\n    cleanup_filtergraph(fg);\n    if (!(fg->graph = avfilter_graph_alloc()))\n        return AVERROR(ENOMEM);\n\n    if (simple) {\n        OutputStream *ost = fg->outputs[0]->ost;\n        char args[512];\n        const AVDictionaryEntry *e = NULL;\n\n        if (filter_nbthreads) {\n            ret = av_opt_set(fg->graph, \"threads\", filter_nbthreads, 0);\n            if (ret < 0)\n                goto fail;\n        } else {\n            e = av_dict_get(ost->encoder_opts, \"threads\", NULL, 0);\n            if (e)\n                av_opt_set(fg->graph, \"threads\", e->value, 0);\n        }\n\n        args[0] = 0;\n        e       = NULL;\n        while ((e = av_dict_get(ost->sws_dict, \"\", e,\n                                AV_DICT_IGNORE_SUFFIX))) {\n            av_strlcatf(args, sizeof(args), \"%s=%s:\", e->key, e->value);\n        }\n        if (strlen(args)) {\n            args[strlen(args)-1] = 0;\n            fg->graph->scale_sws_opts = av_strdup(args);\n        }\n\n        args[0] = 0;\n        e       = NULL;\n        while ((e = av_dict_get(ost->swr_opts, \"\", e,\n                                AV_DICT_IGNORE_SUFFIX))) {\n            av_strlcatf(args, sizeof(args), \"%s=%s:\", e->key, e->value);\n        }\n        if (strlen(args))\n            args[strlen(args)-1] = 0;\n        av_opt_set(fg->graph, \"aresample_swr_opts\", args, 0);\n    } else {\n        fg->graph->nb_threads = filter_complex_nbthreads;\n    }\n\n    if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)\n        goto fail;\n\n    ret = hw_device_setup_for_filter(fg);\n    if (ret < 0)\n        goto fail;\n\n    if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {\n        const char *num_inputs;\n        const char *num_outputs;\n        if (!outputs) {\n            num_outputs = \"0\";\n        } else if (outputs->next) {\n            num_outputs = \">1\";\n        } else {\n            num_outputs = \"1\";\n        }\n        if (!inputs) {\n            num_inputs = \"0\";\n        } else if (inputs->next) {\n            num_inputs = \">1\";\n        } else {\n            num_inputs = \"1\";\n        }\n        av_log(NULL, AV_LOG_ERROR, \"Simple filtergraph '%s' was expected \"\n               \"to have exactly 1 input and 1 output.\"\n               \" However, it had %s input(s) and %s output(s).\"\n               \" Please adjust, or use a complex filtergraph (-filter_complex) instead.\\n\",\n               graph_desc, num_inputs, num_outputs);\n        ret = AVERROR(EINVAL);\n        goto fail;\n    }\n\n    for (cur = inputs, i = 0; cur; cur = cur->next, i++)\n        if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {\n            avfilter_inout_free(&inputs);\n            avfilter_inout_free(&outputs);\n            goto fail;\n        }\n    avfilter_inout_free(&inputs);\n\n    for (cur = outputs, i = 0; cur; cur = cur->next, i++)\n        configure_output_filter(fg, fg->outputs[i], cur);\n    avfilter_inout_free(&outputs);\n\n    if (!auto_conversion_filters)\n        avfilter_graph_set_auto_convert(fg->graph, AVFILTER_AUTO_CONVERT_NONE);\n    if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)\n        goto fail;\n\n    fg->is_meta = graph_is_meta(fg->graph);\n\n    /* limit the lists of allowed formats to the ones selected, to\n     * make sure they stay the same if the filtergraph is reconfigured later */\n    for (i = 0; i < fg->nb_outputs; i++) {\n        OutputFilter *ofilter = fg->outputs[i];\n        AVFilterContext *sink = ofilter->filter;\n\n        ofilter->format = av_buffersink_get_format(sink);\n\n        ofilter->width  = av_buffersink_get_w(sink);\n        ofilter->height = av_buffersink_get_h(sink);\n\n        ofilter->sample_rate    = av_buffersink_get_sample_rate(sink);\n        av_channel_layout_uninit(&ofilter->ch_layout);\n        ret = av_buffersink_get_ch_layout(sink, &ofilter->ch_layout);\n        if (ret < 0)\n            goto fail;\n    }\n\n    fg->reconfiguration = 1;\n\n    for (i = 0; i < fg->nb_outputs; i++) {\n        OutputStream *ost = fg->outputs[i]->ost;\n        if (!ost->enc) {\n            /* identical to the same check in ffmpeg.c, needed because\n               complex filter graphs are initialized earlier */\n            av_log(NULL, AV_LOG_ERROR, \"Encoder (codec %s) not found for output stream #%d:%d\\n\",\n                     avcodec_get_name(ost->st->codecpar->codec_id), ost->file_index, ost->index);\n            ret = AVERROR(EINVAL);\n            goto fail;\n        }\n        if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&\n            !(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))\n            av_buffersink_set_frame_size(ost->filter->filter,\n                                         ost->enc_ctx->frame_size);\n    }\n\n    for (i = 0; i < fg->nb_inputs; i++) {\n        AVFrame *tmp;\n        while (av_fifo_read(fg->inputs[i]->frame_queue, &tmp, 1) >= 0) {\n            ret = av_buffersrc_add_frame(fg->inputs[i]->filter, tmp);\n            av_frame_free(&tmp);\n            if (ret < 0)\n                goto fail;\n        }\n    }\n\n    /* send the EOFs for the finished inputs */\n    for (i = 0; i < fg->nb_inputs; i++) {\n        if (fg->inputs[i]->eof) {\n            ret = av_buffersrc_add_frame(fg->inputs[i]->filter, NULL);\n            if (ret < 0)\n                goto fail;\n        }\n    }\n\n    /* process queued up subtitle packets */\n    for (i = 0; i < fg->nb_inputs; i++) {\n        InputStream *ist = fg->inputs[i]->ist;\n        if (ist->sub2video.sub_queue && ist->sub2video.frame) {\n            AVSubtitle tmp;\n            while (av_fifo_read(ist->sub2video.sub_queue, &tmp, 1) >= 0) {\n                sub2video_update(ist, INT64_MIN, &tmp);\n                avsubtitle_free(&tmp);\n            }\n        }\n    }\n\n    return 0;\n\nfail:\n    cleanup_filtergraph(fg);\n    return ret;\n}\n\nint ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)\n{\n    AVFrameSideData *sd;\n    int ret;\n\n    av_buffer_unref(&ifilter->hw_frames_ctx);\n\n    ifilter->format = frame->format;\n\n    ifilter->width               = frame->width;\n    ifilter->height              = frame->height;\n    ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;\n\n    ifilter->sample_rate         = frame->sample_rate;\n    ret = av_channel_layout_copy(&ifilter->ch_layout, &frame->ch_layout);\n    if (ret < 0)\n        return ret;\n\n    av_freep(&ifilter->displaymatrix);\n    sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);\n    if (sd)\n        ifilter->displaymatrix = av_memdup(sd->data, sizeof(int32_t) * 9);\n\n    if (frame->hw_frames_ctx) {\n        ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx);\n        if (!ifilter->hw_frames_ctx)\n            return AVERROR(ENOMEM);\n    }\n\n    return 0;\n}\n\nint filtergraph_is_simple(FilterGraph *fg)\n{\n    return !fg->graph_desc;\n}\n"
  },
  {
    "path": "src/fftools/ffmpeg_hw.c",
    "content": "/*\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <string.h>\n\n#include \"libavutil/avstring.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavfilter/buffersink.h\"\n\n#include \"ffmpeg.h\"\n\nstatic int nb_hw_devices;\nstatic HWDevice **hw_devices;\n\nstatic HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)\n{\n    HWDevice *found = NULL;\n    int i;\n    for (i = 0; i < nb_hw_devices; i++) {\n        if (hw_devices[i]->type == type) {\n            if (found)\n                return NULL;\n            found = hw_devices[i];\n        }\n    }\n    return found;\n}\n\nHWDevice *hw_device_get_by_name(const char *name)\n{\n    int i;\n    for (i = 0; i < nb_hw_devices; i++) {\n        if (!strcmp(hw_devices[i]->name, name))\n            return hw_devices[i];\n    }\n    return NULL;\n}\n\nstatic HWDevice *hw_device_add(void)\n{\n    int err;\n    err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,\n                            sizeof(*hw_devices));\n    if (err) {\n        nb_hw_devices = 0;\n        return NULL;\n    }\n    hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));\n    if (!hw_devices[nb_hw_devices])\n        return NULL;\n    return hw_devices[nb_hw_devices++];\n}\n\nstatic char *hw_device_default_name(enum AVHWDeviceType type)\n{\n    // Make an automatic name of the form \"type%d\".  We arbitrarily\n    // limit at 1000 anonymous devices of the same type - there is\n    // probably something else very wrong if you get to this limit.\n    const char *type_name = av_hwdevice_get_type_name(type);\n    char *name;\n    size_t index_pos;\n    int index, index_limit = 1000;\n    index_pos = strlen(type_name);\n    name = av_malloc(index_pos + 4);\n    if (!name)\n        return NULL;\n    for (index = 0; index < index_limit; index++) {\n        snprintf(name, index_pos + 4, \"%s%d\", type_name, index);\n        if (!hw_device_get_by_name(name))\n            break;\n    }\n    if (index >= index_limit) {\n        av_freep(&name);\n        return NULL;\n    }\n    return name;\n}\n\nint hw_device_init_from_string(const char *arg, HWDevice **dev_out)\n{\n    // \"type=name\"\n    // \"type=name,key=value,key2=value2\"\n    // \"type=name:device,key=value,key2=value2\"\n    // \"type:device,key=value,key2=value2\"\n    // -> av_hwdevice_ctx_create()\n    // \"type=name@name\"\n    // \"type@name\"\n    // -> av_hwdevice_ctx_create_derived()\n\n    AVDictionary *options = NULL;\n    const char *type_name = NULL, *name = NULL, *device = NULL;\n    enum AVHWDeviceType type;\n    HWDevice *dev, *src;\n    AVBufferRef *device_ref = NULL;\n    int err;\n    const char *errmsg, *p, *q;\n    size_t k;\n\n    k = strcspn(arg, \":=@\");\n    p = arg + k;\n\n    type_name = av_strndup(arg, k);\n    if (!type_name) {\n        err = AVERROR(ENOMEM);\n        goto fail;\n    }\n    type = av_hwdevice_find_type_by_name(type_name);\n    if (type == AV_HWDEVICE_TYPE_NONE) {\n        errmsg = \"unknown device type\";\n        goto invalid;\n    }\n\n    if (*p == '=') {\n        k = strcspn(p + 1, \":@,\");\n\n        name = av_strndup(p + 1, k);\n        if (!name) {\n            err = AVERROR(ENOMEM);\n            goto fail;\n        }\n        if (hw_device_get_by_name(name)) {\n            errmsg = \"named device already exists\";\n            goto invalid;\n        }\n\n        p += 1 + k;\n    } else {\n        name = hw_device_default_name(type);\n        if (!name) {\n            err = AVERROR(ENOMEM);\n            goto fail;\n        }\n    }\n\n    if (!*p) {\n        // New device with no parameters.\n        err = av_hwdevice_ctx_create(&device_ref, type,\n                                     NULL, NULL, 0);\n        if (err < 0)\n            goto fail;\n\n    } else if (*p == ':') {\n        // New device with some parameters.\n        ++p;\n        q = strchr(p, ',');\n        if (q) {\n            if (q - p > 0) {\n                device = av_strndup(p, q - p);\n                if (!device) {\n                    err = AVERROR(ENOMEM);\n                    goto fail;\n                }\n            }\n            err = av_dict_parse_string(&options, q + 1, \"=\", \",\", 0);\n            if (err < 0) {\n                errmsg = \"failed to parse options\";\n                goto invalid;\n            }\n        }\n\n        err = av_hwdevice_ctx_create(&device_ref, type,\n                                     q ? device : p[0] ? p : NULL,\n                                     options, 0);\n        if (err < 0)\n            goto fail;\n\n    } else if (*p == '@') {\n        // Derive from existing device.\n\n        src = hw_device_get_by_name(p + 1);\n        if (!src) {\n            errmsg = \"invalid source device name\";\n            goto invalid;\n        }\n\n        err = av_hwdevice_ctx_create_derived(&device_ref, type,\n                                             src->device_ref, 0);\n        if (err < 0)\n            goto fail;\n    } else if (*p == ',') {\n        err = av_dict_parse_string(&options, p + 1, \"=\", \",\", 0);\n\n        if (err < 0) {\n            errmsg = \"failed to parse options\";\n            goto invalid;\n        }\n\n        err = av_hwdevice_ctx_create(&device_ref, type,\n                                     NULL, options, 0);\n        if (err < 0)\n            goto fail;\n    } else {\n        errmsg = \"parse error\";\n        goto invalid;\n    }\n\n    dev = hw_device_add();\n    if (!dev) {\n        err = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    dev->name = name;\n    dev->type = type;\n    dev->device_ref = device_ref;\n\n    if (dev_out)\n        *dev_out = dev;\n\n    name = NULL;\n    err = 0;\ndone:\n    av_freep(&type_name);\n    av_freep(&name);\n    av_freep(&device);\n    av_dict_free(&options);\n    return err;\ninvalid:\n    av_log(NULL, AV_LOG_ERROR,\n           \"Invalid device specification \\\"%s\\\": %s\\n\", arg, errmsg);\n    err = AVERROR(EINVAL);\n    goto done;\nfail:\n    av_log(NULL, AV_LOG_ERROR,\n           \"Device creation failed: %d.\\n\", err);\n    av_buffer_unref(&device_ref);\n    goto done;\n}\n\nstatic int hw_device_init_from_type(enum AVHWDeviceType type,\n                                    const char *device,\n                                    HWDevice **dev_out)\n{\n    AVBufferRef *device_ref = NULL;\n    HWDevice *dev;\n    char *name;\n    int err;\n\n    name = hw_device_default_name(type);\n    if (!name) {\n        err = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);\n    if (err < 0) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"Device creation failed: %d.\\n\", err);\n        goto fail;\n    }\n\n    dev = hw_device_add();\n    if (!dev) {\n        err = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    dev->name = name;\n    dev->type = type;\n    dev->device_ref = device_ref;\n\n    if (dev_out)\n        *dev_out = dev;\n\n    return 0;\n\nfail:\n    av_freep(&name);\n    av_buffer_unref(&device_ref);\n    return err;\n}\n\nvoid hw_device_free_all(void)\n{\n    int i;\n    for (i = 0; i < nb_hw_devices; i++) {\n        av_freep(&hw_devices[i]->name);\n        av_buffer_unref(&hw_devices[i]->device_ref);\n        av_freep(&hw_devices[i]);\n    }\n    av_freep(&hw_devices);\n    nb_hw_devices = 0;\n}\n\nstatic HWDevice *hw_device_match_by_codec(const AVCodec *codec)\n{\n    const AVCodecHWConfig *config;\n    HWDevice *dev;\n    int i;\n    for (i = 0;; i++) {\n        config = avcodec_get_hw_config(codec, i);\n        if (!config)\n            return NULL;\n        if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))\n            continue;\n        dev = hw_device_get_by_type(config->device_type);\n        if (dev)\n            return dev;\n    }\n}\n\nint hw_device_setup_for_decode(InputStream *ist)\n{\n    const AVCodecHWConfig *config;\n    enum AVHWDeviceType type;\n    HWDevice *dev = NULL;\n    int err, auto_device = 0;\n\n    if (ist->hwaccel_device) {\n        dev = hw_device_get_by_name(ist->hwaccel_device);\n        if (!dev) {\n            if (ist->hwaccel_id == HWACCEL_AUTO) {\n                auto_device = 1;\n            } else if (ist->hwaccel_id == HWACCEL_GENERIC) {\n                type = ist->hwaccel_device_type;\n                err = hw_device_init_from_type(type, ist->hwaccel_device,\n                                               &dev);\n            } else {\n                // This will be dealt with by API-specific initialisation\n                // (using hwaccel_device), so nothing further needed here.\n                return 0;\n            }\n        } else {\n            if (ist->hwaccel_id == HWACCEL_AUTO) {\n                ist->hwaccel_device_type = dev->type;\n            } else if (ist->hwaccel_device_type != dev->type) {\n                av_log(ist->dec_ctx, AV_LOG_ERROR, \"Invalid hwaccel device \"\n                       \"specified for decoder: device %s of type %s is not \"\n                       \"usable with hwaccel %s.\\n\", dev->name,\n                       av_hwdevice_get_type_name(dev->type),\n                       av_hwdevice_get_type_name(ist->hwaccel_device_type));\n                return AVERROR(EINVAL);\n            }\n        }\n    } else {\n        if (ist->hwaccel_id == HWACCEL_AUTO) {\n            auto_device = 1;\n        } else if (ist->hwaccel_id == HWACCEL_GENERIC) {\n            type = ist->hwaccel_device_type;\n            dev = hw_device_get_by_type(type);\n\n            // When \"-qsv_device device\" is used, an internal QSV device named\n            // as \"__qsv_device\" is created. Another QSV device is created too\n            // if \"-init_hw_device qsv=name:device\" is used. There are 2 QSV devices\n            // if both \"-qsv_device device\" and \"-init_hw_device qsv=name:device\"\n            // are used, hw_device_get_by_type(AV_HWDEVICE_TYPE_QSV) returns NULL.\n            // To keep back-compatibility with the removed ad-hoc libmfx setup code,\n            // call hw_device_get_by_name(\"__qsv_device\") to select the internal QSV\n            // device.\n            if (!dev && type == AV_HWDEVICE_TYPE_QSV)\n                dev = hw_device_get_by_name(\"__qsv_device\");\n\n            if (!dev)\n                err = hw_device_init_from_type(type, NULL, &dev);\n        } else {\n            dev = hw_device_match_by_codec(ist->dec);\n            if (!dev) {\n                // No device for this codec, but not using generic hwaccel\n                // and therefore may well not need one - ignore.\n                return 0;\n            }\n        }\n    }\n\n    if (auto_device) {\n        int i;\n        if (!avcodec_get_hw_config(ist->dec, 0)) {\n            // Decoder does not support any hardware devices.\n            return 0;\n        }\n        for (i = 0; !dev; i++) {\n            config = avcodec_get_hw_config(ist->dec, i);\n            if (!config)\n                break;\n            type = config->device_type;\n            dev = hw_device_get_by_type(type);\n            if (dev) {\n                av_log(ist->dec_ctx, AV_LOG_INFO, \"Using auto \"\n                       \"hwaccel type %s with existing device %s.\\n\",\n                       av_hwdevice_get_type_name(type), dev->name);\n            }\n        }\n        for (i = 0; !dev; i++) {\n            config = avcodec_get_hw_config(ist->dec, i);\n            if (!config)\n                break;\n            type = config->device_type;\n            // Try to make a new device of this type.\n            err = hw_device_init_from_type(type, ist->hwaccel_device,\n                                           &dev);\n            if (err < 0) {\n                // Can't make a device of this type.\n                continue;\n            }\n            if (ist->hwaccel_device) {\n                av_log(ist->dec_ctx, AV_LOG_INFO, \"Using auto \"\n                       \"hwaccel type %s with new device created \"\n                       \"from %s.\\n\", av_hwdevice_get_type_name(type),\n                       ist->hwaccel_device);\n            } else {\n                av_log(ist->dec_ctx, AV_LOG_INFO, \"Using auto \"\n                       \"hwaccel type %s with new default device.\\n\",\n                       av_hwdevice_get_type_name(type));\n            }\n        }\n        if (dev) {\n            ist->hwaccel_device_type = type;\n        } else {\n            av_log(ist->dec_ctx, AV_LOG_INFO, \"Auto hwaccel \"\n                   \"disabled: no device found.\\n\");\n            ist->hwaccel_id = HWACCEL_NONE;\n            return 0;\n        }\n    }\n\n    if (!dev) {\n        av_log(ist->dec_ctx, AV_LOG_ERROR, \"No device available \"\n               \"for decoder: device type %s needed for codec %s.\\n\",\n               av_hwdevice_get_type_name(type), ist->dec->name);\n        return err;\n    }\n\n    ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);\n    if (!ist->dec_ctx->hw_device_ctx)\n        return AVERROR(ENOMEM);\n\n    return 0;\n}\n\nint hw_device_setup_for_encode(OutputStream *ost)\n{\n    const AVCodecHWConfig *config;\n    HWDevice *dev = NULL;\n    AVBufferRef *frames_ref = NULL;\n    int i;\n\n    if (ost->filter) {\n        frames_ref = av_buffersink_get_hw_frames_ctx(ost->filter->filter);\n        if (frames_ref &&\n            ((AVHWFramesContext*)frames_ref->data)->format ==\n            ost->enc_ctx->pix_fmt) {\n            // Matching format, will try to use hw_frames_ctx.\n        } else {\n            frames_ref = NULL;\n        }\n    }\n\n    for (i = 0;; i++) {\n        config = avcodec_get_hw_config(ost->enc, i);\n        if (!config)\n            break;\n\n        if (frames_ref &&\n            config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX &&\n            (config->pix_fmt == AV_PIX_FMT_NONE ||\n             config->pix_fmt == ost->enc_ctx->pix_fmt)) {\n            av_log(ost->enc_ctx, AV_LOG_VERBOSE, \"Using input \"\n                   \"frames context (format %s) with %s encoder.\\n\",\n                   av_get_pix_fmt_name(ost->enc_ctx->pix_fmt),\n                   ost->enc->name);\n            ost->enc_ctx->hw_frames_ctx = av_buffer_ref(frames_ref);\n            if (!ost->enc_ctx->hw_frames_ctx)\n                return AVERROR(ENOMEM);\n            return 0;\n        }\n\n        if (!dev &&\n            config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)\n            dev = hw_device_get_by_type(config->device_type);\n    }\n\n    if (dev) {\n        av_log(ost->enc_ctx, AV_LOG_VERBOSE, \"Using device %s \"\n               \"(type %s) with %s encoder.\\n\", dev->name,\n               av_hwdevice_get_type_name(dev->type), ost->enc->name);\n        ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);\n        if (!ost->enc_ctx->hw_device_ctx)\n            return AVERROR(ENOMEM);\n    } else {\n        // No device required, or no device available.\n    }\n    return 0;\n}\n\nstatic int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)\n{\n    InputStream *ist = avctx->opaque;\n    AVFrame *output = NULL;\n    enum AVPixelFormat output_format = ist->hwaccel_output_format;\n    int err;\n\n    if (input->format == output_format) {\n        // Nothing to do.\n        return 0;\n    }\n\n    output = av_frame_alloc();\n    if (!output)\n        return AVERROR(ENOMEM);\n\n    output->format = output_format;\n\n    err = av_hwframe_transfer_data(output, input, 0);\n    if (err < 0) {\n        av_log(avctx, AV_LOG_ERROR, \"Failed to transfer data to \"\n               \"output frame: %d.\\n\", err);\n        goto fail;\n    }\n\n    err = av_frame_copy_props(output, input);\n    if (err < 0) {\n        av_frame_unref(output);\n        goto fail;\n    }\n\n    av_frame_unref(input);\n    av_frame_move_ref(input, output);\n    av_frame_free(&output);\n\n    return 0;\n\nfail:\n    av_frame_free(&output);\n    return err;\n}\n\nint hwaccel_decode_init(AVCodecContext *avctx)\n{\n    InputStream *ist = avctx->opaque;\n\n    ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;\n\n    return 0;\n}\n\nint hw_device_setup_for_filter(FilterGraph *fg)\n{\n    HWDevice *dev;\n    int i;\n\n    // Pick the last hardware device if the user doesn't pick the device for\n    // filters explicitly with the filter_hw_device option.\n    if (filter_hw_device)\n        dev = filter_hw_device;\n    else if (nb_hw_devices > 0) {\n        dev = hw_devices[nb_hw_devices - 1];\n\n        if (nb_hw_devices > 1)\n            av_log(NULL, AV_LOG_WARNING, \"There are %d hardware devices. device \"\n                   \"%s of type %s is picked for filters by default. Set hardware \"\n                   \"device explicitly with the filter_hw_device option if device \"\n                   \"%s is not usable for filters.\\n\",\n                   nb_hw_devices, dev->name,\n                   av_hwdevice_get_type_name(dev->type), dev->name);\n    } else\n        dev = NULL;\n\n    if (dev) {\n        for (i = 0; i < fg->graph->nb_filters; i++) {\n            fg->graph->filters[i]->hw_device_ctx =\n                av_buffer_ref(dev->device_ref);\n            if (!fg->graph->filters[i]->hw_device_ctx)\n                return AVERROR(ENOMEM);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "src/fftools/ffmpeg_mux.c",
    "content": "/*\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"ffmpeg.h\"\n\n#include \"libavutil/fifo.h\"\n#include \"libavutil/intreadwrite.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/mem.h\"\n#include \"libavutil/timestamp.h\"\n\n#include \"libavcodec/packet.h\"\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/avio.h\"\n\nstatic void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others)\n{\n    int i;\n    for (i = 0; i < nb_output_streams; i++) {\n        OutputStream *ost2 = output_streams[i];\n        ost2->finished |= ost == ost2 ? this_stream : others;\n    }\n}\n\nvoid of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost,\n                     int unqueue)\n{\n    AVFormatContext *s = of->ctx;\n    AVStream *st = ost->st;\n    int ret;\n\n    /*\n     * Audio encoders may split the packets --  #frames in != #packets out.\n     * But there is no reordering, so we can limit the number of output packets\n     * by simply dropping them here.\n     * Counting encoded video frames needs to be done separately because of\n     * reordering, see do_video_out().\n     * Do not count the packet when unqueued because it has been counted when queued.\n     */\n    if (!(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->encoding_needed) && !unqueue) {\n        if (ost->frame_number >= ost->max_frames) {\n            av_packet_unref(pkt);\n            return;\n        }\n        ost->frame_number++;\n    }\n\n    if (!of->header_written) {\n        AVPacket *tmp_pkt;\n        /* the muxer is not initialized yet, buffer the packet */\n        if (!av_fifo_can_write(ost->muxing_queue)) {\n            size_t cur_size = av_fifo_can_read(ost->muxing_queue);\n            unsigned int are_we_over_size =\n                (ost->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold;\n            size_t limit    = are_we_over_size ? ost->max_muxing_queue_size : SIZE_MAX;\n            size_t new_size = FFMIN(2 * cur_size, limit);\n\n            if (new_size <= cur_size) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Too many packets buffered for output stream %d:%d.\\n\",\n                       ost->file_index, ost->st->index);\n                exit_program(1);\n            }\n            ret = av_fifo_grow2(ost->muxing_queue, new_size - cur_size);\n            if (ret < 0)\n                exit_program(1);\n        }\n        ret = av_packet_make_refcounted(pkt);\n        if (ret < 0)\n            exit_program(1);\n        tmp_pkt = av_packet_alloc();\n        if (!tmp_pkt)\n            exit_program(1);\n        av_packet_move_ref(tmp_pkt, pkt);\n        ost->muxing_queue_data_size += tmp_pkt->size;\n        av_fifo_write(ost->muxing_queue, &tmp_pkt, 1);\n        return;\n    }\n\n    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP) ||\n        (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))\n        pkt->pts = pkt->dts = AV_NOPTS_VALUE;\n\n    if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {\n        if (ost->frame_rate.num && ost->is_cfr) {\n            if (pkt->duration > 0)\n                av_log(NULL, AV_LOG_WARNING, \"Overriding packet duration by frame rate, this should not happen\\n\");\n            pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),\n                                         ost->mux_timebase);\n        }\n    }\n\n    av_packet_rescale_ts(pkt, ost->mux_timebase, ost->st->time_base);\n\n    if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {\n        if (pkt->dts != AV_NOPTS_VALUE &&\n            pkt->pts != AV_NOPTS_VALUE &&\n            pkt->dts > pkt->pts) {\n            av_log(s, AV_LOG_WARNING, \"Invalid DTS: %\"PRId64\" PTS: %\"PRId64\" in output stream %d:%d, replacing by guess\\n\",\n                   pkt->dts, pkt->pts,\n                   ost->file_index, ost->st->index);\n            pkt->pts =\n            pkt->dts = pkt->pts + pkt->dts + ost->last_mux_dts + 1\n                     - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1)\n                     - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1);\n        }\n        if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) &&\n            pkt->dts != AV_NOPTS_VALUE &&\n            ost->last_mux_dts != AV_NOPTS_VALUE) {\n            int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);\n            if (pkt->dts < max) {\n                int loglevel = max - pkt->dts > 2 || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG;\n                if (exit_on_error)\n                    loglevel = AV_LOG_ERROR;\n                av_log(s, loglevel, \"Non-monotonous DTS in output stream \"\n                       \"%d:%d; previous: %\"PRId64\", current: %\"PRId64\"; \",\n                       ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);\n                if (exit_on_error) {\n                    av_log(NULL, AV_LOG_FATAL, \"aborting.\\n\");\n                    exit_program(1);\n                }\n                av_log(s, loglevel, \"changing to %\"PRId64\". This may result \"\n                       \"in incorrect timestamps in the output file.\\n\",\n                       max);\n                if (pkt->pts >= pkt->dts)\n                    pkt->pts = FFMAX(pkt->pts, max);\n                pkt->dts = max;\n            }\n        }\n    }\n    ost->last_mux_dts = pkt->dts;\n\n    ost->data_size += pkt->size;\n    ost->packets_written++;\n\n    pkt->stream_index = ost->index;\n\n    if (debug_ts) {\n        av_log(NULL, AV_LOG_INFO, \"muxer <- type:%s \"\n                \"pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s size:%d\\n\",\n                av_get_media_type_string(ost->enc_ctx->codec_type),\n                av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base),\n                av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base),\n                av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &ost->st->time_base),\n                pkt->size\n              );\n    }\n\n    ret = av_interleaved_write_frame(s, pkt);\n    if (ret < 0) {\n        print_error(\"av_interleaved_write_frame()\", ret);\n        main_return_code = 1;\n        close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED);\n    }\n}\n\nstatic int print_sdp(void)\n{\n    char sdp[16384];\n    int i;\n    int j, ret;\n    AVIOContext *sdp_pb;\n    AVFormatContext **avc;\n\n    for (i = 0; i < nb_output_files; i++) {\n        if (!output_files[i]->header_written)\n            return 0;\n    }\n\n    avc = av_malloc_array(nb_output_files, sizeof(*avc));\n    if (!avc)\n        exit_program(1);\n    for (i = 0, j = 0; i < nb_output_files; i++) {\n        if (!strcmp(output_files[i]->ctx->oformat->name, \"rtp\")) {\n            avc[j] = output_files[i]->ctx;\n            j++;\n        }\n    }\n\n    if (!j) {\n        av_log(NULL, AV_LOG_ERROR, \"No output streams in the SDP.\\n\");\n        ret = AVERROR(EINVAL);\n        goto fail;\n    }\n\n    ret = av_sdp_create(avc, j, sdp, sizeof(sdp));\n    if (ret < 0)\n        goto fail;\n\n    if (!sdp_filename) {\n        printf(\"SDP:\\n%s\\n\", sdp);\n        fflush(stdout);\n    } else {\n        ret = avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Failed to open sdp file '%s'\\n\", sdp_filename);\n            goto fail;\n        }\n\n        avio_print(sdp_pb, sdp);\n        avio_closep(&sdp_pb);\n        av_freep(&sdp_filename);\n    }\n\nfail:\n    av_freep(&avc);\n    return ret;\n}\n\n/* open the muxer when all the streams are initialized */\nint of_check_init(OutputFile *of)\n{\n    int ret, i;\n\n    for (i = 0; i < of->ctx->nb_streams; i++) {\n        OutputStream *ost = output_streams[of->ost_index + i];\n        if (!ost->initialized)\n            return 0;\n    }\n\n    ret = avformat_write_header(of->ctx, &of->opts);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"Could not write header for output file #%d \"\n               \"(incorrect codec parameters ?): %s\\n\",\n               of->index, av_err2str(ret));\n        return ret;\n    }\n    //assert_avoptions(of->opts);\n    of->header_written = 1;\n\n    av_dump_format(of->ctx, of->index, of->ctx->url, 1);\n    nb_output_dumped++;\n\n    if (sdp_filename || want_sdp) {\n        ret = print_sdp();\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error writing the SDP.\\n\");\n            return ret;\n        }\n    }\n\n    /* flush the muxing queues */\n    for (i = 0; i < of->ctx->nb_streams; i++) {\n        OutputStream *ost = output_streams[of->ost_index + i];\n        AVPacket *pkt;\n\n        /* try to improve muxing time_base (only possible if nothing has been written yet) */\n        if (!av_fifo_can_read(ost->muxing_queue))\n            ost->mux_timebase = ost->st->time_base;\n\n        while (av_fifo_read(ost->muxing_queue, &pkt, 1) >= 0) {\n            ost->muxing_queue_data_size -= pkt->size;\n            of_write_packet(of, pkt, ost, 1);\n            av_packet_free(&pkt);\n        }\n    }\n\n    return 0;\n}\n\nint of_write_trailer(OutputFile *of)\n{\n    int ret;\n\n    if (!of->header_written) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"Nothing was written into output file %d (%s), because \"\n               \"at least one of its streams received no packets.\\n\",\n               of->index, of->ctx->url);\n        return AVERROR(EINVAL);\n    }\n\n    ret = av_write_trailer(of->ctx);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Error writing trailer of %s: %s\\n\", of->ctx->url, av_err2str(ret));\n        return ret;\n    }\n\n    return 0;\n}\n\nvoid of_close(OutputFile **pof)\n{\n    OutputFile *of = *pof;\n    AVFormatContext *s;\n\n    if (!of)\n        return;\n\n    s = of->ctx;\n    if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE))\n        avio_closep(&s->pb);\n    avformat_free_context(s);\n    av_dict_free(&of->opts);\n\n    av_freep(pof);\n}\n"
  },
  {
    "path": "src/fftools/ffmpeg_opt.c",
    "content": "/*\n * ffmpeg option parsing\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"config.h\"\n\n#include <stdint.h>\n\n#if HAVE_SYS_RESOURCE_H\n#include <sys/time.h>\n#include <sys/resource.h>\n#endif\n\n#include \"ffmpeg.h\"\n#include \"fopen_utf8.h\"\n#include \"cmdutils.h\"\n#include \"opt_common.h\"\n\n#include \"libavformat/avformat.h\"\n\n#include \"libavcodec/avcodec.h\"\n#include \"libavcodec/bsf.h\"\n\n#include \"libavfilter/avfilter.h\"\n\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/avutil.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/getenv_utf8.h\"\n#include \"libavutil/intreadwrite.h\"\n#include \"libavutil/fifo.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/pixfmt.h\"\n\n#define DEFAULT_PASS_LOGFILENAME_PREFIX \"ffmpeg2pass\"\n\n#define SPECIFIER_OPT_FMT_str  \"%s\"\n#define SPECIFIER_OPT_FMT_i    \"%i\"\n#define SPECIFIER_OPT_FMT_i64  \"%\"PRId64\n#define SPECIFIER_OPT_FMT_ui64 \"%\"PRIu64\n#define SPECIFIER_OPT_FMT_f    \"%f\"\n#define SPECIFIER_OPT_FMT_dbl  \"%lf\"\n\nstatic const char *const opt_name_codec_names[]               = {\"c\", \"codec\", \"acodec\", \"vcodec\", \"scodec\", \"dcodec\", NULL};\nstatic const char *const opt_name_audio_channels[]            = {\"ac\", NULL};\nstatic const char *const opt_name_audio_ch_layouts[]          = {\"channel_layout\", \"ch_layout\", NULL};\nstatic const char *const opt_name_audio_sample_rate[]         = {\"ar\", NULL};\nstatic const char *const opt_name_frame_rates[]               = {\"r\", NULL};\nstatic const char *const opt_name_max_frame_rates[]           = {\"fpsmax\", NULL};\nstatic const char *const opt_name_frame_sizes[]               = {\"s\", NULL};\nstatic const char *const opt_name_frame_pix_fmts[]            = {\"pix_fmt\", NULL};\nstatic const char *const opt_name_ts_scale[]                  = {\"itsscale\", NULL};\nstatic const char *const opt_name_hwaccels[]                  = {\"hwaccel\", NULL};\nstatic const char *const opt_name_hwaccel_devices[]           = {\"hwaccel_device\", NULL};\nstatic const char *const opt_name_hwaccel_output_formats[]    = {\"hwaccel_output_format\", NULL};\nstatic const char *const opt_name_autorotate[]                = {\"autorotate\", NULL};\nstatic const char *const opt_name_autoscale[]                 = {\"autoscale\", NULL};\nstatic const char *const opt_name_max_frames[]                = {\"frames\", \"aframes\", \"vframes\", \"dframes\", NULL};\nstatic const char *const opt_name_bitstream_filters[]         = {\"bsf\", \"absf\", \"vbsf\", NULL};\nstatic const char *const opt_name_codec_tags[]                = {\"tag\", \"atag\", \"vtag\", \"stag\", NULL};\nstatic const char *const opt_name_sample_fmts[]               = {\"sample_fmt\", NULL};\nstatic const char *const opt_name_qscale[]                    = {\"q\", \"qscale\", NULL};\nstatic const char *const opt_name_forced_key_frames[]         = {\"forced_key_frames\", NULL};\nstatic const char *const opt_name_fps_mode[]                  = {\"fps_mode\", NULL};\nstatic const char *const opt_name_force_fps[]                 = {\"force_fps\", NULL};\nstatic const char *const opt_name_frame_aspect_ratios[]       = {\"aspect\", NULL};\nstatic const char *const opt_name_rc_overrides[]              = {\"rc_override\", NULL};\nstatic const char *const opt_name_intra_matrices[]            = {\"intra_matrix\", NULL};\nstatic const char *const opt_name_inter_matrices[]            = {\"inter_matrix\", NULL};\nstatic const char *const opt_name_chroma_intra_matrices[]     = {\"chroma_intra_matrix\", NULL};\nstatic const char *const opt_name_top_field_first[]           = {\"top\", NULL};\nstatic const char *const opt_name_presets[]                   = {\"pre\", \"apre\", \"vpre\", \"spre\", NULL};\nstatic const char *const opt_name_copy_initial_nonkeyframes[] = {\"copyinkf\", NULL};\nstatic const char *const opt_name_copy_prior_start[]          = {\"copypriorss\", NULL};\nstatic const char *const opt_name_filters[]                   = {\"filter\", \"af\", \"vf\", NULL};\nstatic const char *const opt_name_filter_scripts[]            = {\"filter_script\", NULL};\nstatic const char *const opt_name_reinit_filters[]            = {\"reinit_filter\", NULL};\nstatic const char *const opt_name_fix_sub_duration[]          = {\"fix_sub_duration\", NULL};\nstatic const char *const opt_name_canvas_sizes[]              = {\"canvas_size\", NULL};\nstatic const char *const opt_name_pass[]                      = {\"pass\", NULL};\nstatic const char *const opt_name_passlogfiles[]              = {\"passlogfile\", NULL};\nstatic const char *const opt_name_max_muxing_queue_size[]     = {\"max_muxing_queue_size\", NULL};\nstatic const char *const opt_name_muxing_queue_data_threshold[] = {\"muxing_queue_data_threshold\", NULL};\nstatic const char *const opt_name_guess_layout_max[]          = {\"guess_layout_max\", NULL};\nstatic const char *const opt_name_apad[]                      = {\"apad\", NULL};\nstatic const char *const opt_name_discard[]                   = {\"discard\", NULL};\nstatic const char *const opt_name_disposition[]               = {\"disposition\", NULL};\nstatic const char *const opt_name_time_bases[]                = {\"time_base\", NULL};\nstatic const char *const opt_name_enc_time_bases[]            = {\"enc_time_base\", NULL};\nstatic const char *const opt_name_bits_per_raw_sample[]       = {\"bits_per_raw_sample\", NULL};\n\n#define WARN_MULTIPLE_OPT_USAGE(name, type, so, st)\\\n{\\\n    char namestr[128] = \"\";\\\n    const char *spec = so->specifier && so->specifier[0] ? so->specifier : \"\";\\\n    for (i = 0; opt_name_##name[i]; i++)\\\n        av_strlcatf(namestr, sizeof(namestr), \"-%s%s\", opt_name_##name[i], opt_name_##name[i+1] ? (opt_name_##name[i+2] ? \", \" : \" or \") : \"\");\\\n    av_log(NULL, AV_LOG_WARNING, \"Multiple %s options specified for stream %d, only the last option '-%s%s%s \"SPECIFIER_OPT_FMT_##type\"' will be used.\\n\",\\\n           namestr, st->index, opt_name_##name[0], spec[0] ? \":\" : \"\", spec, so->u.type);\\\n}\n\n#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\\\n{\\\n    int i, ret, matches = 0;\\\n    SpecifierOpt *so;\\\n    for (i = 0; i < o->nb_ ## name; i++) {\\\n        char *spec = o->name[i].specifier;\\\n        if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0) {\\\n            outvar = o->name[i].u.type;\\\n            so = &o->name[i];\\\n            matches++;\\\n        } else if (ret < 0)\\\n            exit_program(1);\\\n    }\\\n    if (matches > 1)\\\n       WARN_MULTIPLE_OPT_USAGE(name, type, so, st);\\\n}\n\n#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\\\n{\\\n    int i;\\\n    for (i = 0; i < o->nb_ ## name; i++) {\\\n        char *spec = o->name[i].specifier;\\\n        if (!strcmp(spec, mediatype))\\\n            outvar = o->name[i].u.type;\\\n    }\\\n}\n\nHWDevice *filter_hw_device;\n\nchar *vstats_filename;\nchar *sdp_filename;\n\nfloat audio_drift_threshold = 0.1;\nfloat dts_delta_threshold   = 10;\nfloat dts_error_threshold   = 3600*30;\n\nint audio_volume      = 256;\nint audio_sync_method = 0;\nenum VideoSyncMethod video_sync_method = VSYNC_AUTO;\nfloat frame_drop_threshold = 0;\nint do_benchmark      = 0;\nint do_benchmark_all  = 0;\nint do_hex_dump       = 0;\nint do_pkt_dump       = 0;\nint copy_ts           = 0;\nint start_at_zero     = 0;\nint copy_tb           = -1;\nint debug_ts          = 0;\nint exit_on_error     = 0;\nint abort_on_flags    = 0;\nint print_stats       = -1;\nint qp_hist           = 0;\nint stdin_interaction = 1;\nfloat max_error_rate  = 2.0/3;\nchar *filter_nbthreads;\nint filter_complex_nbthreads = 0;\nint vstats_version = 2;\nint auto_conversion_filters = 1;\nint64_t stats_period = 500000;\n\n\nstatic int file_overwrite     = 0;\nstatic int no_file_overwrite  = 0;\nstatic int do_psnr            = 0;\nstatic int input_stream_potentially_available = 0;\nstatic int ignore_unknown_streams = 0;\nstatic int copy_unknown_streams = 0;\nstatic int recast_media = 0;\nstatic int find_stream_info = 1;\n\nstatic void uninit_options(OptionsContext *o)\n{\n    const OptionDef *po = options;\n    int i;\n\n    /* all OPT_SPEC and OPT_STRING can be freed in generic way */\n    while (po->name) {\n        void *dst = (uint8_t*)o + po->u.off;\n\n        if (po->flags & OPT_SPEC) {\n            SpecifierOpt **so = dst;\n            int i, *count = (int*)(so + 1);\n            for (i = 0; i < *count; i++) {\n                av_freep(&(*so)[i].specifier);\n                if (po->flags & OPT_STRING)\n                    av_freep(&(*so)[i].u.str);\n            }\n            av_freep(so);\n            *count = 0;\n        } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)\n            av_freep(dst);\n        po++;\n    }\n\n    for (i = 0; i < o->nb_stream_maps; i++)\n        av_freep(&o->stream_maps[i].linklabel);\n    av_freep(&o->stream_maps);\n    av_freep(&o->audio_channel_maps);\n    av_freep(&o->streamid_map);\n    av_freep(&o->attachments);\n}\n\nstatic void init_options(OptionsContext *o)\n{\n    memset(o, 0, sizeof(*o));\n\n    o->stop_time = INT64_MAX;\n    o->mux_max_delay  = 0.7;\n    o->start_time     = AV_NOPTS_VALUE;\n    o->start_time_eof = AV_NOPTS_VALUE;\n    o->recording_time = INT64_MAX;\n    o->limit_filesize = UINT64_MAX;\n    o->chapters_input_file = INT_MAX;\n    o->accurate_seek  = 1;\n    o->thread_queue_size = -1;\n    o->input_sync_ref = -1;\n}\n\nstatic int show_hwaccels(void *optctx, const char *opt, const char *arg)\n{\n    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;\n\n    printf(\"Hardware acceleration methods:\\n\");\n    while ((type = av_hwdevice_iterate_types(type)) !=\n           AV_HWDEVICE_TYPE_NONE)\n        printf(\"%s\\n\", av_hwdevice_get_type_name(type));\n    printf(\"\\n\");\n    return 0;\n}\n\n/* return a copy of the input with the stream specifiers removed from the keys */\nstatic AVDictionary *strip_specifiers(AVDictionary *dict)\n{\n    const AVDictionaryEntry *e = NULL;\n    AVDictionary    *ret = NULL;\n\n    while ((e = av_dict_get(dict, \"\", e, AV_DICT_IGNORE_SUFFIX))) {\n        char *p = strchr(e->key, ':');\n\n        if (p)\n            *p = 0;\n        av_dict_set(&ret, e->key, e->value, 0);\n        if (p)\n            *p = ':';\n    }\n    return ret;\n}\n\nstatic int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)\n{\n    if      (!av_strcasecmp(arg, \"cfr\"))         *vsync_var = VSYNC_CFR;\n    else if (!av_strcasecmp(arg, \"vfr\"))         *vsync_var = VSYNC_VFR;\n    else if (!av_strcasecmp(arg, \"passthrough\")) *vsync_var = VSYNC_PASSTHROUGH;\n    else if (!av_strcasecmp(arg, \"drop\"))        *vsync_var = VSYNC_DROP;\n    else if (!is_global && !av_strcasecmp(arg, \"auto\"))  *vsync_var = VSYNC_AUTO;\n    else if (!is_global) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid value %s specified for fps_mode of #%d:%d.\\n\", arg, file_idx, st_idx);\n        exit_program(1);\n    }\n\n    if (is_global && *vsync_var == VSYNC_AUTO) {\n        video_sync_method = parse_number_or_die(\"vsync\", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);\n        av_log(NULL, AV_LOG_WARNING, \"Passing a number to -vsync is deprecated,\"\n               \" use a string argument as described in the manual.\\n\");\n    }\n    return 0;\n}\n\nstatic int apply_sync_offsets(void)\n{\n    for (int i = 0; i < nb_input_files; i++) {\n        InputFile *ref, *self = input_files[i];\n        int64_t adjustment;\n        int64_t self_start_time, ref_start_time, self_seek_start, ref_seek_start;\n        int start_times_set = 1;\n\n        if (self->input_sync_ref == -1 || self->input_sync_ref == i) continue;\n        if (self->input_sync_ref >= nb_input_files || self->input_sync_ref < -1) {\n            av_log(NULL, AV_LOG_FATAL, \"-isync for input %d references non-existent input %d.\\n\", i, self->input_sync_ref);\n            exit_program(1);\n        }\n\n        if (copy_ts && !start_at_zero) {\n            av_log(NULL, AV_LOG_FATAL, \"Use of -isync requires that start_at_zero be set if copyts is set.\\n\");\n            exit_program(1);\n        }\n\n        ref = input_files[self->input_sync_ref];\n        if (ref->input_sync_ref != -1 && ref->input_sync_ref != self->input_sync_ref) {\n            av_log(NULL, AV_LOG_ERROR, \"-isync for input %d references a resynced input %d. Sync not set.\\n\", i, self->input_sync_ref);\n            continue;\n        }\n\n        if (self->ctx->start_time_realtime != AV_NOPTS_VALUE && ref->ctx->start_time_realtime != AV_NOPTS_VALUE) {\n            self_start_time = self->ctx->start_time_realtime;\n            ref_start_time  =  ref->ctx->start_time_realtime;\n        } else if (self->ctx->start_time != AV_NOPTS_VALUE && ref->ctx->start_time != AV_NOPTS_VALUE) {\n            self_start_time = self->ctx->start_time;\n            ref_start_time  =  ref->ctx->start_time;\n        } else {\n            start_times_set = 0;\n        }\n\n        if (start_times_set) {\n            self_seek_start = self->start_time == AV_NOPTS_VALUE ? 0 : self->start_time;\n            ref_seek_start  =  ref->start_time == AV_NOPTS_VALUE ? 0 :  ref->start_time;\n\n            adjustment = (self_start_time - ref_start_time) + !copy_ts*(self_seek_start - ref_seek_start) + ref->input_ts_offset;\n\n            self->ts_offset += adjustment;\n\n            av_log(NULL, AV_LOG_INFO, \"Adjusted ts offset for Input #%d by %\"PRId64\" us to sync with Input #%d.\\n\", i, adjustment, self->input_sync_ref);\n        } else {\n            av_log(NULL, AV_LOG_INFO, \"Unable to identify start times for Inputs #%d and %d both. No sync adjustment made.\\n\", i, self->input_sync_ref);\n        }\n    }\n\n    return 0;\n}\n\nstatic int opt_filter_threads(void *optctx, const char *opt, const char *arg)\n{\n    av_free(filter_nbthreads);\n    filter_nbthreads = av_strdup(arg);\n    return 0;\n}\n\nstatic int opt_abort_on(void *optctx, const char *opt, const char *arg)\n{\n    static const AVOption opts[] = {\n        { \"abort_on\"           , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX,           .unit = \"flags\" },\n        { \"empty_output\"       , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT        }, .unit = \"flags\" },\n        { \"empty_output_stream\", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM }, .unit = \"flags\" },\n        { NULL },\n    };\n    static const AVClass class = {\n        .class_name = \"\",\n        .item_name  = av_default_item_name,\n        .option     = opts,\n        .version    = LIBAVUTIL_VERSION_INT,\n    };\n    const AVClass *pclass = &class;\n\n    return av_opt_eval_flags(&pclass, &opts[0], arg, &abort_on_flags);\n}\n\nstatic int opt_stats_period(void *optctx, const char *opt, const char *arg)\n{\n    int64_t user_stats_period = parse_time_or_die(opt, arg, 1);\n\n    if (user_stats_period <= 0) {\n        av_log(NULL, AV_LOG_ERROR, \"stats_period %s must be positive.\\n\", arg);\n        return AVERROR(EINVAL);\n    }\n\n    stats_period = user_stats_period;\n    av_log(NULL, AV_LOG_INFO, \"ffmpeg stats and -progress period set to %s.\\n\", arg);\n\n    return 0;\n}\n\nstatic int opt_audio_codec(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"codec:a\", arg, options);\n}\n\nstatic int opt_video_codec(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"codec:v\", arg, options);\n}\n\nstatic int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"codec:s\", arg, options);\n}\n\nstatic int opt_data_codec(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"codec:d\", arg, options);\n}\n\nstatic int opt_map(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    StreamMap *m = NULL;\n    int i, negative = 0, file_idx, disabled = 0;\n    int sync_file_idx = -1, sync_stream_idx = 0;\n    char *p, *sync;\n    char *map;\n    char *allow_unused;\n\n    if (*arg == '-') {\n        negative = 1;\n        arg++;\n    }\n    map = av_strdup(arg);\n    if (!map)\n        return AVERROR(ENOMEM);\n\n    /* parse sync stream first, just pick first matching stream */\n    if (sync = strchr(map, ',')) {\n        *sync = 0;\n        sync_file_idx = strtol(sync + 1, &sync, 0);\n        if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid sync file index: %d.\\n\", sync_file_idx);\n            exit_program(1);\n        }\n        if (*sync)\n            sync++;\n        for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)\n            if (check_stream_specifier(input_files[sync_file_idx]->ctx,\n                                       input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {\n                sync_stream_idx = i;\n                break;\n            }\n        if (i == input_files[sync_file_idx]->nb_streams) {\n            av_log(NULL, AV_LOG_FATAL, \"Sync stream specification in map %s does not \"\n                                       \"match any streams.\\n\", arg);\n            exit_program(1);\n        }\n        if (input_streams[input_files[sync_file_idx]->ist_index + sync_stream_idx]->user_set_discard == AVDISCARD_ALL) {\n            av_log(NULL, AV_LOG_FATAL, \"Sync stream specification in map %s matches a disabled input \"\n                                       \"stream.\\n\", arg);\n            exit_program(1);\n        }\n    }\n\n\n    if (map[0] == '[') {\n        /* this mapping refers to lavfi output */\n        const char *c = map + 1;\n        GROW_ARRAY(o->stream_maps, o->nb_stream_maps);\n        m = &o->stream_maps[o->nb_stream_maps - 1];\n        m->linklabel = av_get_token(&c, \"]\");\n        if (!m->linklabel) {\n            av_log(NULL, AV_LOG_ERROR, \"Invalid output link label: %s.\\n\", map);\n            exit_program(1);\n        }\n    } else {\n        if (allow_unused = strchr(map, '?'))\n            *allow_unused = 0;\n        file_idx = strtol(map, &p, 0);\n        if (file_idx >= nb_input_files || file_idx < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid input file index: %d.\\n\", file_idx);\n            exit_program(1);\n        }\n        if (negative)\n            /* disable some already defined maps */\n            for (i = 0; i < o->nb_stream_maps; i++) {\n                m = &o->stream_maps[i];\n                if (file_idx == m->file_index &&\n                    check_stream_specifier(input_files[m->file_index]->ctx,\n                                           input_files[m->file_index]->ctx->streams[m->stream_index],\n                                           *p == ':' ? p + 1 : p) > 0)\n                    m->disabled = 1;\n            }\n        else\n            for (i = 0; i < input_files[file_idx]->nb_streams; i++) {\n                if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i],\n                            *p == ':' ? p + 1 : p) <= 0)\n                    continue;\n                if (input_streams[input_files[file_idx]->ist_index + i]->user_set_discard == AVDISCARD_ALL) {\n                    disabled = 1;\n                    continue;\n                }\n                GROW_ARRAY(o->stream_maps, o->nb_stream_maps);\n                m = &o->stream_maps[o->nb_stream_maps - 1];\n\n                m->file_index   = file_idx;\n                m->stream_index = i;\n\n                if (sync_file_idx >= 0) {\n                    m->sync_file_index   = sync_file_idx;\n                    m->sync_stream_index = sync_stream_idx;\n                } else {\n                    m->sync_file_index   = file_idx;\n                    m->sync_stream_index = i;\n                }\n            }\n    }\n\n    if (!m) {\n        if (allow_unused) {\n            av_log(NULL, AV_LOG_VERBOSE, \"Stream map '%s' matches no streams; ignoring.\\n\", arg);\n        } else if (disabled) {\n            av_log(NULL, AV_LOG_FATAL, \"Stream map '%s' matches disabled streams.\\n\"\n                                       \"To ignore this, add a trailing '?' to the map.\\n\", arg);\n            exit_program(1);\n        } else {\n            av_log(NULL, AV_LOG_FATAL, \"Stream map '%s' matches no streams.\\n\"\n                                       \"To ignore this, add a trailing '?' to the map.\\n\", arg);\n            exit_program(1);\n        }\n    }\n\n    av_freep(&map);\n    return 0;\n}\n\nstatic int opt_attach(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    GROW_ARRAY(o->attachments, o->nb_attachments);\n    o->attachments[o->nb_attachments - 1] = arg;\n    return 0;\n}\n\nstatic int opt_map_channel(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    int n;\n    AVStream *st;\n    AudioChannelMap *m;\n    char *allow_unused;\n    char *mapchan;\n    mapchan = av_strdup(arg);\n    if (!mapchan)\n        return AVERROR(ENOMEM);\n\n    GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);\n    m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];\n\n    /* muted channel syntax */\n    n = sscanf(arg, \"%d:%d.%d\", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);\n    if ((n == 1 || n == 3) && m->channel_idx == -1) {\n        m->file_idx = m->stream_idx = -1;\n        if (n == 1)\n            m->ofile_idx = m->ostream_idx = -1;\n        av_free(mapchan);\n        return 0;\n    }\n\n    /* normal syntax */\n    n = sscanf(arg, \"%d.%d.%d:%d.%d\",\n               &m->file_idx,  &m->stream_idx, &m->channel_idx,\n               &m->ofile_idx, &m->ostream_idx);\n\n    if (n != 3 && n != 5) {\n        av_log(NULL, AV_LOG_FATAL, \"Syntax error, mapchan usage: \"\n               \"[file.stream.channel|-1][:syncfile:syncstream]\\n\");\n        exit_program(1);\n    }\n\n    if (n != 5) // only file.stream.channel specified\n        m->ofile_idx = m->ostream_idx = -1;\n\n    /* check input */\n    if (m->file_idx < 0 || m->file_idx >= nb_input_files) {\n        av_log(NULL, AV_LOG_FATAL, \"mapchan: invalid input file index: %d\\n\",\n               m->file_idx);\n        exit_program(1);\n    }\n    if (m->stream_idx < 0 ||\n        m->stream_idx >= input_files[m->file_idx]->nb_streams) {\n        av_log(NULL, AV_LOG_FATAL, \"mapchan: invalid input file stream index #%d.%d\\n\",\n               m->file_idx, m->stream_idx);\n        exit_program(1);\n    }\n    st = input_files[m->file_idx]->ctx->streams[m->stream_idx];\n    if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) {\n        av_log(NULL, AV_LOG_FATAL, \"mapchan: stream #%d.%d is not an audio stream.\\n\",\n               m->file_idx, m->stream_idx);\n        exit_program(1);\n    }\n    /* allow trailing ? to map_channel */\n    if (allow_unused = strchr(mapchan, '?'))\n        *allow_unused = 0;\n    if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->ch_layout.nb_channels ||\n        input_streams[input_files[m->file_idx]->ist_index + m->stream_idx]->user_set_discard == AVDISCARD_ALL) {\n        if (allow_unused) {\n            av_log(NULL, AV_LOG_VERBOSE, \"mapchan: invalid audio channel #%d.%d.%d\\n\",\n                    m->file_idx, m->stream_idx, m->channel_idx);\n        } else {\n            av_log(NULL, AV_LOG_FATAL,  \"mapchan: invalid audio channel #%d.%d.%d\\n\"\n                    \"To ignore this, add a trailing '?' to the map_channel.\\n\",\n                    m->file_idx, m->stream_idx, m->channel_idx);\n            exit_program(1);\n        }\n\n    }\n    av_free(mapchan);\n    return 0;\n}\n\nstatic int opt_sdp_file(void *optctx, const char *opt, const char *arg)\n{\n    av_free(sdp_filename);\n    sdp_filename = av_strdup(arg);\n    return 0;\n}\n\n#if CONFIG_VAAPI\nstatic int opt_vaapi_device(void *optctx, const char *opt, const char *arg)\n{\n    const char *prefix = \"vaapi:\";\n    char *tmp;\n    int err;\n    tmp = av_asprintf(\"%s%s\", prefix, arg);\n    if (!tmp)\n        return AVERROR(ENOMEM);\n    err = hw_device_init_from_string(tmp, NULL);\n    av_free(tmp);\n    return err;\n}\n#endif\n\n#if CONFIG_QSV\nstatic int opt_qsv_device(void *optctx, const char *opt, const char *arg)\n{\n    const char *prefix = \"qsv=__qsv_device:hw_any,child_device=\";\n    int err;\n    char *tmp = av_asprintf(\"%s%s\", prefix, arg);\n\n    if (!tmp)\n        return AVERROR(ENOMEM);\n\n    err = hw_device_init_from_string(tmp, NULL);\n    av_free(tmp);\n\n    return err;\n}\n#endif\n\nstatic int opt_init_hw_device(void *optctx, const char *opt, const char *arg)\n{\n    if (!strcmp(arg, \"list\")) {\n        enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;\n        printf(\"Supported hardware device types:\\n\");\n        while ((type = av_hwdevice_iterate_types(type)) !=\n               AV_HWDEVICE_TYPE_NONE)\n            printf(\"%s\\n\", av_hwdevice_get_type_name(type));\n        printf(\"\\n\");\n        exit_program(0);\n    } else {\n        return hw_device_init_from_string(arg, NULL);\n    }\n}\n\nstatic int opt_filter_hw_device(void *optctx, const char *opt, const char *arg)\n{\n    if (filter_hw_device) {\n        av_log(NULL, AV_LOG_ERROR, \"Only one filter device can be used.\\n\");\n        return AVERROR(EINVAL);\n    }\n    filter_hw_device = hw_device_get_by_name(arg);\n    if (!filter_hw_device) {\n        av_log(NULL, AV_LOG_ERROR, \"Invalid filter device %s.\\n\", arg);\n        return AVERROR(EINVAL);\n    }\n    return 0;\n}\n\n/**\n * Parse a metadata specifier passed as 'arg' parameter.\n * @param arg  metadata string to parse\n * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)\n * @param index for type c/p, chapter/program index is written here\n * @param stream_spec for type s, the stream specifier is written here\n */\nstatic void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)\n{\n    if (*arg) {\n        *type = *arg;\n        switch (*arg) {\n        case 'g':\n            break;\n        case 's':\n            if (*(++arg) && *arg != ':') {\n                av_log(NULL, AV_LOG_FATAL, \"Invalid metadata specifier %s.\\n\", arg);\n                exit_program(1);\n            }\n            *stream_spec = *arg == ':' ? arg + 1 : \"\";\n            break;\n        case 'c':\n        case 'p':\n            if (*(++arg) == ':')\n                *index = strtol(++arg, NULL, 0);\n            break;\n        default:\n            av_log(NULL, AV_LOG_FATAL, \"Invalid metadata type %c.\\n\", *arg);\n            exit_program(1);\n        }\n    } else\n        *type = 'g';\n}\n\nstatic int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)\n{\n    AVDictionary **meta_in = NULL;\n    AVDictionary **meta_out = NULL;\n    int i, ret = 0;\n    char type_in, type_out;\n    const char *istream_spec = NULL, *ostream_spec = NULL;\n    int idx_in = 0, idx_out = 0;\n\n    parse_meta_type(inspec,  &type_in,  &idx_in,  &istream_spec);\n    parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);\n\n    if (!ic) {\n        if (type_out == 'g' || !*outspec)\n            o->metadata_global_manual = 1;\n        if (type_out == 's' || !*outspec)\n            o->metadata_streams_manual = 1;\n        if (type_out == 'c' || !*outspec)\n            o->metadata_chapters_manual = 1;\n        return 0;\n    }\n\n    if (type_in == 'g' || type_out == 'g')\n        o->metadata_global_manual = 1;\n    if (type_in == 's' || type_out == 's')\n        o->metadata_streams_manual = 1;\n    if (type_in == 'c' || type_out == 'c')\n        o->metadata_chapters_manual = 1;\n\n    /* ic is NULL when just disabling automatic mappings */\n    if (!ic)\n        return 0;\n\n#define METADATA_CHECK_INDEX(index, nb_elems, desc)\\\n    if ((index) < 0 || (index) >= (nb_elems)) {\\\n        av_log(NULL, AV_LOG_FATAL, \"Invalid %s index %d while processing metadata maps.\\n\",\\\n                (desc), (index));\\\n        exit_program(1);\\\n    }\n\n#define SET_DICT(type, meta, context, index)\\\n        switch (type) {\\\n        case 'g':\\\n            meta = &context->metadata;\\\n            break;\\\n        case 'c':\\\n            METADATA_CHECK_INDEX(index, context->nb_chapters, \"chapter\")\\\n            meta = &context->chapters[index]->metadata;\\\n            break;\\\n        case 'p':\\\n            METADATA_CHECK_INDEX(index, context->nb_programs, \"program\")\\\n            meta = &context->programs[index]->metadata;\\\n            break;\\\n        case 's':\\\n            break; /* handled separately below */ \\\n        default: av_assert0(0);\\\n        }\\\n\n    SET_DICT(type_in, meta_in, ic, idx_in);\n    SET_DICT(type_out, meta_out, oc, idx_out);\n\n    /* for input streams choose first matching stream */\n    if (type_in == 's') {\n        for (i = 0; i < ic->nb_streams; i++) {\n            if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {\n                meta_in = &ic->streams[i]->metadata;\n                break;\n            } else if (ret < 0)\n                exit_program(1);\n        }\n        if (!meta_in) {\n            av_log(NULL, AV_LOG_FATAL, \"Stream specifier %s does not match  any streams.\\n\", istream_spec);\n            exit_program(1);\n        }\n    }\n\n    if (type_out == 's') {\n        for (i = 0; i < oc->nb_streams; i++) {\n            if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {\n                meta_out = &oc->streams[i]->metadata;\n                av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);\n            } else if (ret < 0)\n                exit_program(1);\n        }\n    } else\n        av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);\n\n    return 0;\n}\n\nstatic int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    char buf[128];\n    int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;\n    struct tm time = *gmtime((time_t*)&recording_timestamp);\n    if (!strftime(buf, sizeof(buf), \"creation_time=%Y-%m-%dT%H:%M:%S%z\", &time))\n        return -1;\n    parse_option(o, \"metadata\", buf, options);\n\n    av_log(NULL, AV_LOG_WARNING, \"%s is deprecated, set the 'creation_time' metadata \"\n                                 \"tag instead.\\n\", opt);\n    return 0;\n}\n\nstatic const AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)\n{\n    const AVCodecDescriptor *desc;\n    const char *codec_string = encoder ? \"encoder\" : \"decoder\";\n    const AVCodec *codec;\n\n    codec = encoder ?\n        avcodec_find_encoder_by_name(name) :\n        avcodec_find_decoder_by_name(name);\n\n    if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {\n        codec = encoder ? avcodec_find_encoder(desc->id) :\n                          avcodec_find_decoder(desc->id);\n        if (codec)\n            av_log(NULL, AV_LOG_VERBOSE, \"Matched %s '%s' for codec '%s'.\\n\",\n                   codec_string, codec->name, desc->name);\n    }\n\n    if (!codec) {\n        av_log(NULL, AV_LOG_FATAL, \"Unknown %s '%s'\\n\", codec_string, name);\n        exit_program(1);\n    }\n    if (codec->type != type && !recast_media) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid %s type '%s'\\n\", codec_string, name);\n        exit_program(1);\n    }\n    return codec;\n}\n\nstatic const AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)\n{\n    char *codec_name = NULL;\n\n    MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);\n    if (codec_name) {\n        const AVCodec *codec = find_codec_or_die(codec_name, st->codecpar->codec_type, 0);\n        st->codecpar->codec_id = codec->id;\n        if (recast_media && st->codecpar->codec_type != codec->type)\n            st->codecpar->codec_type = codec->type;\n        return codec;\n    } else\n        return avcodec_find_decoder(st->codecpar->codec_id);\n}\n\n/* Add all the streams from the given input file to the global\n * list of input streams. */\nstatic void add_input_streams(OptionsContext *o, AVFormatContext *ic)\n{\n    int i, ret;\n\n    for (i = 0; i < ic->nb_streams; i++) {\n        AVStream *st = ic->streams[i];\n        AVCodecParameters *par = st->codecpar;\n        InputStream *ist;\n        char *framerate = NULL, *hwaccel_device = NULL;\n        const char *hwaccel = NULL;\n        char *hwaccel_output_format = NULL;\n        char *codec_tag = NULL;\n        char *next;\n        char *discard_str = NULL;\n        const AVClass *cc = avcodec_get_class();\n        const AVOption *discard_opt = av_opt_find(&cc, \"skip_frame\", NULL,\n                                                  0, AV_OPT_SEARCH_FAKE_OBJ);\n\n        ist = ALLOC_ARRAY_ELEM(input_streams, nb_input_streams);\n        ist->st = st;\n        ist->file_index = nb_input_files;\n        ist->discard = 1;\n        st->discard  = AVDISCARD_ALL;\n        ist->nb_samples = 0;\n        ist->first_dts = AV_NOPTS_VALUE;\n        ist->min_pts = INT64_MAX;\n        ist->max_pts = INT64_MIN;\n\n        ist->ts_scale = 1.0;\n        MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);\n\n        ist->autorotate = 1;\n        MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);\n\n        MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);\n        if (codec_tag) {\n            uint32_t tag = strtol(codec_tag, &next, 0);\n            if (*next)\n                tag = AV_RL32(codec_tag);\n            st->codecpar->codec_tag = tag;\n        }\n\n        ist->dec = choose_decoder(o, ic, st);\n        ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codecpar->codec_id, ic, st, ist->dec);\n\n        ist->reinit_filters = -1;\n        MATCH_PER_STREAM_OPT(reinit_filters, i, ist->reinit_filters, ic, st);\n\n        MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);\n        ist->user_set_discard = AVDISCARD_NONE;\n\n        if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||\n            (o->audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ||\n            (o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) ||\n            (o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA))\n                ist->user_set_discard = AVDISCARD_ALL;\n\n        if (discard_str && av_opt_eval_int(&cc, discard_opt, discard_str, &ist->user_set_discard) < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error parsing discard %s.\\n\",\n                    discard_str);\n            exit_program(1);\n        }\n\n        ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;\n        ist->prev_pkt_pts = AV_NOPTS_VALUE;\n\n        ist->dec_ctx = avcodec_alloc_context3(ist->dec);\n        if (!ist->dec_ctx) {\n            av_log(NULL, AV_LOG_ERROR, \"Error allocating the decoder context.\\n\");\n            exit_program(1);\n        }\n\n        ret = avcodec_parameters_to_context(ist->dec_ctx, par);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error initializing the decoder context.\\n\");\n            exit_program(1);\n        }\n\n        ist->decoded_frame = av_frame_alloc();\n        if (!ist->decoded_frame)\n            exit_program(1);\n\n        ist->pkt = av_packet_alloc();\n        if (!ist->pkt)\n            exit_program(1);\n\n        if (o->bitexact)\n            ist->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT;\n\n        switch (par->codec_type) {\n        case AVMEDIA_TYPE_VIDEO:\n            if(!ist->dec)\n                ist->dec = avcodec_find_decoder(par->codec_id);\n\n            // avformat_find_stream_info() doesn't set this for us anymore.\n            ist->dec_ctx->framerate = st->avg_frame_rate;\n\n            MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);\n            if (framerate && av_parse_video_rate(&ist->framerate,\n                                                 framerate) < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"Error parsing framerate %s.\\n\",\n                       framerate);\n                exit_program(1);\n            }\n\n            ist->top_field_first = -1;\n            MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);\n\n            MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);\n            MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,\n                                 hwaccel_output_format, ic, st);\n\n            if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, \"cuvid\")) {\n                av_log(NULL, AV_LOG_WARNING,\n                    \"WARNING: defaulting hwaccel_output_format to cuda for compatibility \"\n                    \"with old commandlines. This behaviour is DEPRECATED and will be removed \"\n                    \"in the future. Please explicitly set \\\"-hwaccel_output_format cuda\\\".\\n\");\n                ist->hwaccel_output_format = AV_PIX_FMT_CUDA;\n            } else if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, \"qsv\")) {\n                av_log(NULL, AV_LOG_WARNING,\n                    \"WARNING: defaulting hwaccel_output_format to qsv for compatibility \"\n                    \"with old commandlines. This behaviour is DEPRECATED and will be removed \"\n                    \"in the future. Please explicitly set \\\"-hwaccel_output_format qsv\\\".\\n\");\n                ist->hwaccel_output_format = AV_PIX_FMT_QSV;\n            } else if (hwaccel_output_format) {\n                ist->hwaccel_output_format = av_get_pix_fmt(hwaccel_output_format);\n                if (ist->hwaccel_output_format == AV_PIX_FMT_NONE) {\n                    av_log(NULL, AV_LOG_FATAL, \"Unrecognised hwaccel output \"\n                           \"format: %s\", hwaccel_output_format);\n                }\n            } else {\n                ist->hwaccel_output_format = AV_PIX_FMT_NONE;\n            }\n\n            if (hwaccel) {\n                // The NVDEC hwaccels use a CUDA device, so remap the name here.\n                if (!strcmp(hwaccel, \"nvdec\") || !strcmp(hwaccel, \"cuvid\"))\n                    hwaccel = \"cuda\";\n\n                if (!strcmp(hwaccel, \"none\"))\n                    ist->hwaccel_id = HWACCEL_NONE;\n                else if (!strcmp(hwaccel, \"auto\"))\n                    ist->hwaccel_id = HWACCEL_AUTO;\n                else {\n                    enum AVHWDeviceType type = av_hwdevice_find_type_by_name(hwaccel);\n                    if (type != AV_HWDEVICE_TYPE_NONE) {\n                        ist->hwaccel_id = HWACCEL_GENERIC;\n                        ist->hwaccel_device_type = type;\n                    }\n\n                    if (!ist->hwaccel_id) {\n                        av_log(NULL, AV_LOG_FATAL, \"Unrecognized hwaccel: %s.\\n\",\n                               hwaccel);\n                        av_log(NULL, AV_LOG_FATAL, \"Supported hwaccels: \");\n                        type = AV_HWDEVICE_TYPE_NONE;\n                        while ((type = av_hwdevice_iterate_types(type)) !=\n                               AV_HWDEVICE_TYPE_NONE)\n                            av_log(NULL, AV_LOG_FATAL, \"%s \",\n                                   av_hwdevice_get_type_name(type));\n                        av_log(NULL, AV_LOG_FATAL, \"\\n\");\n                        exit_program(1);\n                    }\n                }\n            }\n\n            MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);\n            if (hwaccel_device) {\n                ist->hwaccel_device = av_strdup(hwaccel_device);\n                if (!ist->hwaccel_device)\n                    exit_program(1);\n            }\n\n            ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;\n\n            break;\n        case AVMEDIA_TYPE_AUDIO:\n            ist->guess_layout_max = INT_MAX;\n            MATCH_PER_STREAM_OPT(guess_layout_max, i, ist->guess_layout_max, ic, st);\n            guess_input_channel_layout(ist);\n            break;\n        case AVMEDIA_TYPE_DATA:\n        case AVMEDIA_TYPE_SUBTITLE: {\n            char *canvas_size = NULL;\n            if(!ist->dec)\n                ist->dec = avcodec_find_decoder(par->codec_id);\n            MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);\n            MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);\n            if (canvas_size &&\n                av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, canvas_size) < 0) {\n                av_log(NULL, AV_LOG_FATAL, \"Invalid canvas size: %s.\\n\", canvas_size);\n                exit_program(1);\n            }\n            break;\n        }\n        case AVMEDIA_TYPE_ATTACHMENT:\n        case AVMEDIA_TYPE_UNKNOWN:\n            break;\n        default:\n            abort();\n        }\n\n        ret = avcodec_parameters_from_context(par, ist->dec_ctx);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error initializing the decoder context.\\n\");\n            exit_program(1);\n        }\n    }\n}\n\nstatic void assert_file_overwrite(const char *filename)\n{\n    const char *proto_name = avio_find_protocol_name(filename);\n\n    if (file_overwrite && no_file_overwrite) {\n        fprintf(stderr, \"Error, both -y and -n supplied. Exiting.\\n\");\n        exit_program(1);\n    }\n\n    if (!file_overwrite) {\n        if (proto_name && !strcmp(proto_name, \"file\") && avio_check(filename, 0) == 0) {\n            if (stdin_interaction && !no_file_overwrite) {\n                fprintf(stderr,\"File '%s' already exists. Overwrite? [y/N] \", filename);\n                fflush(stderr);\n                term_exit();\n                signal(SIGINT, SIG_DFL);\n                if (!read_yesno()) {\n                    av_log(NULL, AV_LOG_FATAL, \"Not overwriting - exiting\\n\");\n                    exit_program(1);\n                }\n                term_init();\n            }\n            else {\n                av_log(NULL, AV_LOG_FATAL, \"File '%s' already exists. Exiting.\\n\", filename);\n                exit_program(1);\n            }\n        }\n    }\n\n    if (proto_name && !strcmp(proto_name, \"file\")) {\n        for (int i = 0; i < nb_input_files; i++) {\n             InputFile *file = input_files[i];\n             if (file->ctx->iformat->flags & AVFMT_NOFILE)\n                 continue;\n             if (!strcmp(filename, file->ctx->url)) {\n                 av_log(NULL, AV_LOG_FATAL, \"Output %s same as Input #%d - exiting\\n\", filename, i);\n                 av_log(NULL, AV_LOG_WARNING, \"FFmpeg cannot edit existing files in-place.\\n\");\n                 exit_program(1);\n             }\n        }\n    }\n}\n\nstatic void dump_attachment(AVStream *st, const char *filename)\n{\n    int ret;\n    AVIOContext *out = NULL;\n    const AVDictionaryEntry *e;\n\n    if (!st->codecpar->extradata_size) {\n        av_log(NULL, AV_LOG_WARNING, \"No extradata to dump in stream #%d:%d.\\n\",\n               nb_input_files - 1, st->index);\n        return;\n    }\n    if (!*filename && (e = av_dict_get(st->metadata, \"filename\", NULL, 0)))\n        filename = e->value;\n    if (!*filename) {\n        av_log(NULL, AV_LOG_FATAL, \"No filename specified and no 'filename' tag\"\n               \"in stream #%d:%d.\\n\", nb_input_files - 1, st->index);\n        exit_program(1);\n    }\n\n    assert_file_overwrite(filename);\n\n    if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not open file %s for writing.\\n\",\n               filename);\n        exit_program(1);\n    }\n\n    avio_write(out, st->codecpar->extradata, st->codecpar->extradata_size);\n    avio_flush(out);\n    avio_close(out);\n}\n\nstatic int open_input_file(OptionsContext *o, const char *filename)\n{\n    InputFile *f;\n    AVFormatContext *ic;\n    const AVInputFormat *file_iformat = NULL;\n    int err, i, ret;\n    int64_t timestamp;\n    AVDictionary *unused_opts = NULL;\n    const AVDictionaryEntry *e = NULL;\n    char *   video_codec_name = NULL;\n    char *   audio_codec_name = NULL;\n    char *subtitle_codec_name = NULL;\n    char *    data_codec_name = NULL;\n    int scan_all_pmts_set = 0;\n\n    if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {\n        o->stop_time = INT64_MAX;\n        av_log(NULL, AV_LOG_WARNING, \"-t and -to cannot be used together; using -t.\\n\");\n    }\n\n    if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {\n        int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;\n        if (o->stop_time <= start_time) {\n            av_log(NULL, AV_LOG_ERROR, \"-to value smaller than -ss; aborting.\\n\");\n            exit_program(1);\n        } else {\n            o->recording_time = o->stop_time - start_time;\n        }\n    }\n\n    if (o->format) {\n        if (!(file_iformat = av_find_input_format(o->format))) {\n            av_log(NULL, AV_LOG_FATAL, \"Unknown input format: '%s'\\n\", o->format);\n            exit_program(1);\n        }\n    }\n\n    if (!strcmp(filename, \"-\"))\n        filename = \"pipe:\";\n\n    stdin_interaction &= strncmp(filename, \"pipe:\", 5) &&\n                         strcmp(filename, \"/dev/stdin\");\n\n    /* get default parameters from command line */\n    ic = avformat_alloc_context();\n    if (!ic) {\n        print_error(filename, AVERROR(ENOMEM));\n        exit_program(1);\n    }\n    if (o->nb_audio_sample_rate) {\n        av_dict_set_int(&o->g->format_opts, \"sample_rate\", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);\n    }\n    if (o->nb_audio_channels) {\n        const AVClass *priv_class;\n        if (file_iformat && (priv_class = file_iformat->priv_class) &&\n            av_opt_find(&priv_class, \"ch_layout\", NULL, 0,\n                        AV_OPT_SEARCH_FAKE_OBJ)) {\n            char buf[32];\n            snprintf(buf, sizeof(buf), \"%dC\", o->audio_channels[o->nb_audio_channels - 1].u.i);\n            av_dict_set(&o->g->format_opts, \"ch_layout\", buf, 0);\n        }\n    }\n    if (o->nb_audio_ch_layouts) {\n        const AVClass *priv_class;\n        if (file_iformat && (priv_class = file_iformat->priv_class) &&\n            av_opt_find(&priv_class, \"ch_layout\", NULL, 0,\n                        AV_OPT_SEARCH_FAKE_OBJ)) {\n            av_dict_set(&o->g->format_opts, \"ch_layout\", o->audio_ch_layouts[o->nb_audio_ch_layouts - 1].u.str, 0);\n        }\n    }\n    if (o->nb_frame_rates) {\n        const AVClass *priv_class;\n        /* set the format-level framerate option;\n         * this is important for video grabbers, e.g. x11 */\n        if (file_iformat && (priv_class = file_iformat->priv_class) &&\n            av_opt_find(&priv_class, \"framerate\", NULL, 0,\n                        AV_OPT_SEARCH_FAKE_OBJ)) {\n            av_dict_set(&o->g->format_opts, \"framerate\",\n                        o->frame_rates[o->nb_frame_rates - 1].u.str, 0);\n        }\n    }\n    if (o->nb_frame_sizes) {\n        av_dict_set(&o->g->format_opts, \"video_size\", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);\n    }\n    if (o->nb_frame_pix_fmts)\n        av_dict_set(&o->g->format_opts, \"pixel_format\", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);\n\n    MATCH_PER_TYPE_OPT(codec_names, str,    video_codec_name, ic, \"v\");\n    MATCH_PER_TYPE_OPT(codec_names, str,    audio_codec_name, ic, \"a\");\n    MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, \"s\");\n    MATCH_PER_TYPE_OPT(codec_names, str,     data_codec_name, ic, \"d\");\n\n    if (video_codec_name)\n        ic->video_codec    = find_codec_or_die(video_codec_name   , AVMEDIA_TYPE_VIDEO   , 0);\n    if (audio_codec_name)\n        ic->audio_codec    = find_codec_or_die(audio_codec_name   , AVMEDIA_TYPE_AUDIO   , 0);\n    if (subtitle_codec_name)\n        ic->subtitle_codec = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0);\n    if (data_codec_name)\n        ic->data_codec     = find_codec_or_die(data_codec_name    , AVMEDIA_TYPE_DATA    , 0);\n\n    ic->video_codec_id     = video_codec_name    ? ic->video_codec->id    : AV_CODEC_ID_NONE;\n    ic->audio_codec_id     = audio_codec_name    ? ic->audio_codec->id    : AV_CODEC_ID_NONE;\n    ic->subtitle_codec_id  = subtitle_codec_name ? ic->subtitle_codec->id : AV_CODEC_ID_NONE;\n    ic->data_codec_id      = data_codec_name     ? ic->data_codec->id     : AV_CODEC_ID_NONE;\n\n    ic->flags |= AVFMT_FLAG_NONBLOCK;\n    if (o->bitexact)\n        ic->flags |= AVFMT_FLAG_BITEXACT;\n    ic->interrupt_callback = int_cb;\n\n    if (!av_dict_get(o->g->format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE)) {\n        av_dict_set(&o->g->format_opts, \"scan_all_pmts\", \"1\", AV_DICT_DONT_OVERWRITE);\n        scan_all_pmts_set = 1;\n    }\n    /* open the input file with generic avformat function */\n    err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);\n    if (err < 0) {\n        print_error(filename, err);\n        if (err == AVERROR_PROTOCOL_NOT_FOUND)\n            av_log(NULL, AV_LOG_ERROR, \"Did you mean file:%s?\\n\", filename);\n        exit_program(1);\n    }\n    if (scan_all_pmts_set)\n        av_dict_set(&o->g->format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE);\n    remove_avoptions(&o->g->format_opts, o->g->codec_opts);\n    assert_avoptions(o->g->format_opts);\n\n    /* apply forced codec ids */\n    for (i = 0; i < ic->nb_streams; i++)\n        choose_decoder(o, ic, ic->streams[i]);\n\n    if (find_stream_info) {\n        AVDictionary **opts = setup_find_stream_info_opts(ic, o->g->codec_opts);\n        int orig_nb_streams = ic->nb_streams;\n\n        /* If not enough info to get the stream parameters, we decode the\n           first frames to get it. (used in mpeg case for example) */\n        ret = avformat_find_stream_info(ic, opts);\n\n        for (i = 0; i < orig_nb_streams; i++)\n            av_dict_free(&opts[i]);\n        av_freep(&opts);\n\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"%s: could not find codec parameters\\n\", filename);\n            if (ic->nb_streams == 0) {\n                avformat_close_input(&ic);\n                exit_program(1);\n            }\n        }\n    }\n\n    if (o->start_time != AV_NOPTS_VALUE && o->start_time_eof != AV_NOPTS_VALUE) {\n        av_log(NULL, AV_LOG_WARNING, \"Cannot use -ss and -sseof both, using -ss for %s\\n\", filename);\n        o->start_time_eof = AV_NOPTS_VALUE;\n    }\n\n    if (o->start_time_eof != AV_NOPTS_VALUE) {\n        if (o->start_time_eof >= 0) {\n            av_log(NULL, AV_LOG_ERROR, \"-sseof value must be negative; aborting\\n\");\n            exit_program(1);\n        }\n        if (ic->duration > 0) {\n            o->start_time = o->start_time_eof + ic->duration;\n            if (o->start_time < 0) {\n                av_log(NULL, AV_LOG_WARNING, \"-sseof value seeks to before start of file %s; ignored\\n\", filename);\n                o->start_time = AV_NOPTS_VALUE;\n            }\n        } else\n            av_log(NULL, AV_LOG_WARNING, \"Cannot use -sseof, duration of %s not known\\n\", filename);\n    }\n    timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;\n    /* add the stream start time */\n    if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)\n        timestamp += ic->start_time;\n\n    /* if seeking requested, we execute it */\n    if (o->start_time != AV_NOPTS_VALUE) {\n        int64_t seek_timestamp = timestamp;\n\n        if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) {\n            int dts_heuristic = 0;\n            for (i=0; i<ic->nb_streams; i++) {\n                const AVCodecParameters *par = ic->streams[i]->codecpar;\n                if (par->video_delay) {\n                    dts_heuristic = 1;\n                    break;\n                }\n            }\n            if (dts_heuristic) {\n                seek_timestamp -= 3*AV_TIME_BASE / 23;\n            }\n        }\n        ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_WARNING, \"%s: could not seek to position %0.3f\\n\",\n                   filename, (double)timestamp / AV_TIME_BASE);\n        }\n    }\n\n    /* update the current parameters so that they match the one of the input stream */\n    add_input_streams(o, ic);\n\n    /* dump the file content */\n    av_dump_format(ic, nb_input_files, filename, 0);\n\n    f = ALLOC_ARRAY_ELEM(input_files, nb_input_files);\n\n    f->ctx        = ic;\n    f->ist_index  = nb_input_streams - ic->nb_streams;\n    f->start_time = o->start_time;\n    f->recording_time = o->recording_time;\n    f->input_sync_ref = o->input_sync_ref;\n    f->input_ts_offset = o->input_ts_offset;\n    f->ts_offset  = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);\n    f->nb_streams = ic->nb_streams;\n    f->rate_emu   = o->rate_emu;\n    f->accurate_seek = o->accurate_seek;\n    f->loop = o->loop;\n    f->duration = 0;\n    f->time_base = (AVRational){ 1, 1 };\n\n    f->readrate = o->readrate ? o->readrate : 0.0;\n    if (f->readrate < 0.0f) {\n        av_log(NULL, AV_LOG_ERROR, \"Option -readrate for Input #%d is %0.3f; it must be non-negative.\\n\", nb_input_files, f->readrate);\n        exit_program(1);\n    }\n    if (f->readrate && f->rate_emu) {\n        av_log(NULL, AV_LOG_WARNING, \"Both -readrate and -re set for Input #%d. Using -readrate %0.3f.\\n\", nb_input_files, f->readrate);\n        f->rate_emu = 0;\n    }\n\n    f->pkt = av_packet_alloc();\n    if (!f->pkt)\n        exit_program(1);\n#if HAVE_THREADS\n    f->thread_queue_size = o->thread_queue_size;\n#endif\n\n    /* check if all codec options have been used */\n    unused_opts = strip_specifiers(o->g->codec_opts);\n    for (i = f->ist_index; i < nb_input_streams; i++) {\n        e = NULL;\n        while ((e = av_dict_get(input_streams[i]->decoder_opts, \"\", e,\n                                AV_DICT_IGNORE_SUFFIX)))\n            av_dict_set(&unused_opts, e->key, NULL, 0);\n    }\n\n    e = NULL;\n    while ((e = av_dict_get(unused_opts, \"\", e, AV_DICT_IGNORE_SUFFIX))) {\n        const AVClass *class = avcodec_get_class();\n        const AVOption *option = av_opt_find(&class, e->key, NULL, 0,\n                                             AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);\n        const AVClass *fclass = avformat_get_class();\n        const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,\n                                             AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);\n        if (!option || foption)\n            continue;\n\n\n        if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {\n            av_log(NULL, AV_LOG_ERROR, \"Codec AVOption %s (%s) specified for \"\n                   \"input file #%d (%s) is not a decoding option.\\n\", e->key,\n                   option->help ? option->help : \"\", nb_input_files - 1,\n                   filename);\n            exit_program(1);\n        }\n\n        av_log(NULL, AV_LOG_WARNING, \"Codec AVOption %s (%s) specified for \"\n               \"input file #%d (%s) has not been used for any stream. The most \"\n               \"likely reason is either wrong type (e.g. a video option with \"\n               \"no video streams) or that it is a private option of some decoder \"\n               \"which was not actually used for any stream.\\n\", e->key,\n               option->help ? option->help : \"\", nb_input_files - 1, filename);\n    }\n    av_dict_free(&unused_opts);\n\n    for (i = 0; i < o->nb_dump_attachment; i++) {\n        int j;\n\n        for (j = 0; j < ic->nb_streams; j++) {\n            AVStream *st = ic->streams[j];\n\n            if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)\n                dump_attachment(st, o->dump_attachment[i].u.str);\n        }\n    }\n\n    input_stream_potentially_available = 1;\n\n    return 0;\n}\n\nstatic char *get_line(AVIOContext *s, AVBPrint *bprint)\n{\n    char c;\n\n    while ((c = avio_r8(s)) && c != '\\n')\n        av_bprint_chars(bprint, c, 1);\n\n    if (!av_bprint_is_complete(bprint)) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not alloc buffer for reading preset.\\n\");\n        exit_program(1);\n    }\n    return bprint->str;\n}\n\nstatic int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)\n{\n    int i, ret = -1;\n    char filename[1000];\n    char *env_avconv_datadir = getenv_utf8(\"AVCONV_DATADIR\");\n    char *env_home = getenv_utf8(\"HOME\");\n    const char *base[3] = { env_avconv_datadir,\n                            env_home,\n                            AVCONV_DATADIR,\n                            };\n\n    for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {\n        if (!base[i])\n            continue;\n        if (codec_name) {\n            snprintf(filename, sizeof(filename), \"%s%s/%s-%s.avpreset\", base[i],\n                     i != 1 ? \"\" : \"/.avconv\", codec_name, preset_name);\n            ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);\n        }\n        if (ret < 0) {\n            snprintf(filename, sizeof(filename), \"%s%s/%s.avpreset\", base[i],\n                     i != 1 ? \"\" : \"/.avconv\", preset_name);\n            ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);\n        }\n    }\n    freeenv_utf8(env_home);\n    freeenv_utf8(env_avconv_datadir);\n    return ret;\n}\n\nstatic int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)\n{\n    enum AVMediaType type = ost->st->codecpar->codec_type;\n    char *codec_name = NULL;\n\n    if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) {\n        MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);\n        if (!codec_name) {\n            ost->st->codecpar->codec_id = av_guess_codec(s->oformat, NULL, s->url,\n                                                         NULL, ost->st->codecpar->codec_type);\n            ost->enc = avcodec_find_encoder(ost->st->codecpar->codec_id);\n            if (!ost->enc) {\n                av_log(NULL, AV_LOG_FATAL, \"Automatic encoder selection failed for \"\n                       \"output stream #%d:%d. Default encoder for format %s (codec %s) is \"\n                       \"probably disabled. Please choose an encoder manually.\\n\",\n                       ost->file_index, ost->index, s->oformat->name,\n                       avcodec_get_name(ost->st->codecpar->codec_id));\n                return AVERROR_ENCODER_NOT_FOUND;\n            }\n        } else if (!strcmp(codec_name, \"copy\"))\n            ost->stream_copy = 1;\n        else {\n            ost->enc = find_codec_or_die(codec_name, ost->st->codecpar->codec_type, 1);\n            ost->st->codecpar->codec_id = ost->enc->id;\n        }\n        ost->encoding_needed = !ost->stream_copy;\n    } else {\n        /* no encoding supported for other media types */\n        ost->stream_copy     = 1;\n        ost->encoding_needed = 0;\n    }\n\n    return 0;\n}\n\nstatic OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)\n{\n    OutputStream *ost;\n    AVStream *st = avformat_new_stream(oc, NULL);\n    int idx      = oc->nb_streams - 1, ret = 0;\n    const char *bsfs = NULL, *time_base = NULL;\n    char *next, *codec_tag = NULL;\n    double qscale = -1;\n    int i;\n\n    if (!st) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not alloc stream.\\n\");\n        exit_program(1);\n    }\n\n    if (oc->nb_streams - 1 < o->nb_streamid_map)\n        st->id = o->streamid_map[oc->nb_streams - 1];\n\n    ost = ALLOC_ARRAY_ELEM(output_streams, nb_output_streams);\n\n    ost->file_index = nb_output_files - 1;\n    ost->index      = idx;\n    ost->st         = st;\n    ost->forced_kf_ref_pts = AV_NOPTS_VALUE;\n    st->codecpar->codec_type = type;\n\n    ret = choose_encoder(o, oc, ost);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error selecting an encoder for stream \"\n               \"%d:%d\\n\", ost->file_index, ost->index);\n        exit_program(1);\n    }\n\n    ost->enc_ctx = avcodec_alloc_context3(ost->enc);\n    if (!ost->enc_ctx) {\n        av_log(NULL, AV_LOG_ERROR, \"Error allocating the encoding context.\\n\");\n        exit_program(1);\n    }\n    ost->enc_ctx->codec_type = type;\n\n    ost->ref_par = avcodec_parameters_alloc();\n    if (!ost->ref_par) {\n        av_log(NULL, AV_LOG_ERROR, \"Error allocating the encoding parameters.\\n\");\n        exit_program(1);\n    }\n\n    ost->filtered_frame = av_frame_alloc();\n    if (!ost->filtered_frame)\n        exit_program(1);\n\n    ost->pkt = av_packet_alloc();\n    if (!ost->pkt)\n        exit_program(1);\n\n    if (ost->enc) {\n        AVIOContext *s = NULL;\n        char *buf = NULL, *arg = NULL, *preset = NULL;\n\n        ost->encoder_opts  = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);\n\n        MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);\n        ost->autoscale = 1;\n        MATCH_PER_STREAM_OPT(autoscale, i, ost->autoscale, oc, st);\n        if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {\n            AVBPrint bprint;\n            av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);\n            do  {\n                av_bprint_clear(&bprint);\n                buf = get_line(s, &bprint);\n                if (!buf[0] || buf[0] == '#')\n                    continue;\n                if (!(arg = strchr(buf, '='))) {\n                    av_log(NULL, AV_LOG_FATAL, \"Invalid line found in the preset file.\\n\");\n                    exit_program(1);\n                }\n                *arg++ = 0;\n                av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);\n            } while (!s->eof_reached);\n            av_bprint_finalize(&bprint, NULL);\n            avio_closep(&s);\n        }\n        if (ret) {\n            av_log(NULL, AV_LOG_FATAL,\n                   \"Preset %s specified for stream %d:%d, but could not be opened.\\n\",\n                   preset, ost->file_index, ost->index);\n            exit_program(1);\n        }\n    } else {\n        ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);\n    }\n\n\n    if (o->bitexact)\n        ost->enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT;\n\n    MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st);\n    if (time_base) {\n        AVRational q;\n        if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||\n            q.num <= 0 || q.den <= 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid time base: %s\\n\", time_base);\n            exit_program(1);\n        }\n        st->time_base = q;\n    }\n\n    MATCH_PER_STREAM_OPT(enc_time_bases, str, time_base, oc, st);\n    if (time_base) {\n        AVRational q;\n        if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||\n            q.den <= 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid time base: %s\\n\", time_base);\n            exit_program(1);\n        }\n        ost->enc_timebase = q;\n    }\n\n    ost->max_frames = INT64_MAX;\n    MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);\n    for (i = 0; i<o->nb_max_frames; i++) {\n        char *p = o->max_frames[i].specifier;\n        if (!*p && type != AVMEDIA_TYPE_VIDEO) {\n            av_log(NULL, AV_LOG_WARNING, \"Applying unspecific -frames to non video streams, maybe you meant -vframes ?\\n\");\n            break;\n        }\n    }\n\n    ost->copy_prior_start = -1;\n    MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);\n\n    MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st);\n    if (bsfs && *bsfs) {\n        ret = av_bsf_list_parse_str(bsfs, &ost->bsf_ctx);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error parsing bitstream filter sequence '%s': %s\\n\", bsfs, av_err2str(ret));\n            exit_program(1);\n        }\n    }\n\n    MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);\n    if (codec_tag) {\n        uint32_t tag = strtol(codec_tag, &next, 0);\n        if (*next)\n            tag = AV_RL32(codec_tag);\n        ost->st->codecpar->codec_tag =\n        ost->enc_ctx->codec_tag = tag;\n    }\n\n    MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);\n    if (qscale >= 0) {\n        ost->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;\n        ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;\n    }\n\n    MATCH_PER_STREAM_OPT(disposition, str, ost->disposition, oc, st);\n    ost->disposition = av_strdup(ost->disposition);\n\n    ost->max_muxing_queue_size = 128;\n    MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, ost->max_muxing_queue_size, oc, st);\n\n    ost->muxing_queue_data_size = 0;\n\n    ost->muxing_queue_data_threshold = 50*1024*1024;\n    MATCH_PER_STREAM_OPT(muxing_queue_data_threshold, i, ost->muxing_queue_data_threshold, oc, st);\n\n    MATCH_PER_STREAM_OPT(bits_per_raw_sample, i, ost->bits_per_raw_sample,\n                         oc, st);\n\n    if (oc->oformat->flags & AVFMT_GLOBALHEADER)\n        ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;\n\n    av_dict_copy(&ost->sws_dict, o->g->sws_dict, 0);\n\n    av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);\n    if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)\n        av_dict_set(&ost->swr_opts, \"output_sample_bits\", \"24\", 0);\n\n    ost->source_index = source_index;\n    if (source_index >= 0) {\n        ost->sync_ist = input_streams[source_index];\n        input_streams[source_index]->discard = 0;\n        input_streams[source_index]->st->discard = input_streams[source_index]->user_set_discard;\n    }\n    ost->last_mux_dts = AV_NOPTS_VALUE;\n\n    ost->muxing_queue = av_fifo_alloc2(8, sizeof(AVPacket*), 0);\n    if (!ost->muxing_queue)\n        exit_program(1);\n\n    MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i,\n                         ost->copy_initial_nonkeyframes, oc, st);\n\n    return ost;\n}\n\nstatic void parse_matrix_coeffs(uint16_t *dest, const char *str)\n{\n    int i;\n    const char *p = str;\n    for (i = 0;; i++) {\n        dest[i] = atoi(p);\n        if (i == 63)\n            break;\n        p = strchr(p, ',');\n        if (!p) {\n            av_log(NULL, AV_LOG_FATAL, \"Syntax error in matrix \\\"%s\\\" at coeff %d\\n\", str, i);\n            exit_program(1);\n        }\n        p++;\n    }\n}\n\n/* read file contents into a string */\nstatic char *read_file(const char *filename)\n{\n    AVIOContext *pb      = NULL;\n    int ret = avio_open(&pb, filename, AVIO_FLAG_READ);\n    AVBPrint bprint;\n    char *str;\n\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Error opening file %s.\\n\", filename);\n        return NULL;\n    }\n\n    av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);\n    ret = avio_read_to_bprint(pb, &bprint, SIZE_MAX);\n    avio_closep(&pb);\n    if (ret < 0) {\n        av_bprint_finalize(&bprint, NULL);\n        return NULL;\n    }\n    ret = av_bprint_finalize(&bprint, &str);\n    if (ret < 0)\n        return NULL;\n    return str;\n}\n\nstatic char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,\n                             OutputStream *ost)\n{\n    AVStream *st = ost->st;\n\n    if (ost->filters_script && ost->filters) {\n        av_log(NULL, AV_LOG_ERROR, \"Both -filter and -filter_script set for \"\n               \"output stream #%d:%d.\\n\", nb_output_files, st->index);\n        exit_program(1);\n    }\n\n    if (ost->filters_script)\n        return read_file(ost->filters_script);\n    else if (ost->filters)\n        return av_strdup(ost->filters);\n\n    return av_strdup(st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ?\n                     \"null\" : \"anull\");\n}\n\nstatic void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc,\n                                     const OutputStream *ost, enum AVMediaType type)\n{\n    if (ost->filters_script || ost->filters) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"%s '%s' was defined for %s output stream %d:%d but codec copy was selected.\\n\"\n               \"Filtering and streamcopy cannot be used together.\\n\",\n               ost->filters ? \"Filtergraph\" : \"Filtergraph script\",\n               ost->filters ? ost->filters : ost->filters_script,\n               av_get_media_type_string(type), ost->file_index, ost->index);\n        exit_program(1);\n    }\n}\n\nstatic OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    AVStream *st;\n    OutputStream *ost;\n    AVCodecContext *video_enc;\n    char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;\n\n    ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);\n    st  = ost->st;\n    video_enc = ost->enc_ctx;\n\n    MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);\n    if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid framerate value: %s\\n\", frame_rate);\n        exit_program(1);\n    }\n\n    MATCH_PER_STREAM_OPT(max_frame_rates, str, max_frame_rate, oc, st);\n    if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid maximum framerate value: %s\\n\", max_frame_rate);\n        exit_program(1);\n    }\n\n    if (frame_rate && max_frame_rate) {\n        av_log(NULL, AV_LOG_ERROR, \"Only one of -fpsmax and -r can be set for a stream.\\n\");\n        exit_program(1);\n    }\n\n    if ((frame_rate || max_frame_rate) &&\n        video_sync_method == VSYNC_PASSTHROUGH)\n        av_log(NULL, AV_LOG_ERROR, \"Using -vsync passthrough and -r/-fpsmax can produce invalid output files\\n\");\n\n    MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);\n    if (frame_aspect_ratio) {\n        AVRational q;\n        if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||\n            q.num <= 0 || q.den <= 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid aspect ratio: %s\\n\", frame_aspect_ratio);\n            exit_program(1);\n        }\n        ost->frame_aspect_ratio = q;\n    }\n\n    MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);\n    MATCH_PER_STREAM_OPT(filters,        str, ost->filters,        oc, st);\n\n    if (!ost->stream_copy) {\n        const char *p = NULL;\n        char *frame_size = NULL;\n        char *frame_pix_fmt = NULL;\n        char *intra_matrix = NULL, *inter_matrix = NULL;\n        char *chroma_intra_matrix = NULL;\n        int do_pass = 0;\n        int i;\n\n        MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);\n        if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid frame size: %s.\\n\", frame_size);\n            exit_program(1);\n        }\n\n        MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);\n        if (frame_pix_fmt && *frame_pix_fmt == '+') {\n            ost->keep_pix_fmt = 1;\n            if (!*++frame_pix_fmt)\n                frame_pix_fmt = NULL;\n        }\n        if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {\n            av_log(NULL, AV_LOG_FATAL, \"Unknown pixel format requested: %s.\\n\", frame_pix_fmt);\n            exit_program(1);\n        }\n        st->sample_aspect_ratio = video_enc->sample_aspect_ratio;\n\n        MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);\n        if (intra_matrix) {\n            if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {\n                av_log(NULL, AV_LOG_FATAL, \"Could not allocate memory for intra matrix.\\n\");\n                exit_program(1);\n            }\n            parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);\n        }\n        MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);\n        if (chroma_intra_matrix) {\n            uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);\n            if (!p) {\n                av_log(NULL, AV_LOG_FATAL, \"Could not allocate memory for intra matrix.\\n\");\n                exit_program(1);\n            }\n            video_enc->chroma_intra_matrix = p;\n            parse_matrix_coeffs(p, chroma_intra_matrix);\n        }\n        MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);\n        if (inter_matrix) {\n            if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {\n                av_log(NULL, AV_LOG_FATAL, \"Could not allocate memory for inter matrix.\\n\");\n                exit_program(1);\n            }\n            parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);\n        }\n\n        MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);\n        for (i = 0; p; i++) {\n            int start, end, q;\n            int e = sscanf(p, \"%d,%d,%d\", &start, &end, &q);\n            if (e != 3) {\n                av_log(NULL, AV_LOG_FATAL, \"error parsing rc_override\\n\");\n                exit_program(1);\n            }\n            video_enc->rc_override =\n                av_realloc_array(video_enc->rc_override,\n                                 i + 1, sizeof(RcOverride));\n            if (!video_enc->rc_override) {\n                av_log(NULL, AV_LOG_FATAL, \"Could not (re)allocate memory for rc_override.\\n\");\n                exit_program(1);\n            }\n            video_enc->rc_override[i].start_frame = start;\n            video_enc->rc_override[i].end_frame   = end;\n            if (q > 0) {\n                video_enc->rc_override[i].qscale         = q;\n                video_enc->rc_override[i].quality_factor = 1.0;\n            }\n            else {\n                video_enc->rc_override[i].qscale         = 0;\n                video_enc->rc_override[i].quality_factor = -q/100.0;\n            }\n            p = strchr(p, '/');\n            if (p) p++;\n        }\n        video_enc->rc_override_count = i;\n\n        if (do_psnr)\n            video_enc->flags|= AV_CODEC_FLAG_PSNR;\n\n        /* two pass mode */\n        MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);\n        if (do_pass) {\n            if (do_pass & 1) {\n                video_enc->flags |= AV_CODEC_FLAG_PASS1;\n                av_dict_set(&ost->encoder_opts, \"flags\", \"+pass1\", AV_DICT_APPEND);\n            }\n            if (do_pass & 2) {\n                video_enc->flags |= AV_CODEC_FLAG_PASS2;\n                av_dict_set(&ost->encoder_opts, \"flags\", \"+pass2\", AV_DICT_APPEND);\n            }\n        }\n\n        MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);\n        if (ost->logfile_prefix &&\n            !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))\n            exit_program(1);\n\n        if (do_pass) {\n            char logfilename[1024];\n            FILE *f;\n\n            snprintf(logfilename, sizeof(logfilename), \"%s-%d.log\",\n                     ost->logfile_prefix ? ost->logfile_prefix :\n                                           DEFAULT_PASS_LOGFILENAME_PREFIX,\n                     nb_output_streams - 1);\n            if (!strcmp(ost->enc->name, \"libx264\")) {\n                av_dict_set(&ost->encoder_opts, \"stats\", logfilename, AV_DICT_DONT_OVERWRITE);\n            } else {\n                if (video_enc->flags & AV_CODEC_FLAG_PASS2) {\n                    char  *logbuffer = read_file(logfilename);\n\n                    if (!logbuffer) {\n                        av_log(NULL, AV_LOG_FATAL, \"Error reading log file '%s' for pass-2 encoding\\n\",\n                               logfilename);\n                        exit_program(1);\n                    }\n                    video_enc->stats_in = logbuffer;\n                }\n                if (video_enc->flags & AV_CODEC_FLAG_PASS1) {\n                    f = fopen_utf8(logfilename, \"wb\");\n                    if (!f) {\n                        av_log(NULL, AV_LOG_FATAL,\n                               \"Cannot write log file '%s' for pass-1 encoding: %s\\n\",\n                               logfilename, strerror(errno));\n                        exit_program(1);\n                    }\n                    ost->logfile = f;\n                }\n            }\n        }\n\n        MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);\n        if (ost->forced_keyframes)\n            ost->forced_keyframes = av_strdup(ost->forced_keyframes);\n\n        MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);\n\n        ost->top_field_first = -1;\n        MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);\n\n        ost->vsync_method = video_sync_method;\n        MATCH_PER_STREAM_OPT(fps_mode, str, ost->fps_mode, oc, st);\n        if (ost->fps_mode)\n            parse_and_set_vsync(ost->fps_mode, &ost->vsync_method, ost->file_index, ost->index, 0);\n\n        if (ost->vsync_method == VSYNC_AUTO) {\n            if (!strcmp(oc->oformat->name, \"avi\")) {\n                ost->vsync_method = VSYNC_VFR;\n            } else {\n                ost->vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS)       ?\n                                     ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ?\n                                      VSYNC_PASSTHROUGH : VSYNC_VFR)                :\n                                     VSYNC_CFR;\n            }\n\n            if (ost->source_index >= 0 && ost->vsync_method == VSYNC_CFR) {\n                const InputStream *ist = input_streams[ost->source_index];\n                const InputFile *ifile = input_files[ist->file_index];\n\n                if (ifile->nb_streams == 1 && ifile->input_ts_offset == 0)\n                    ost->vsync_method = VSYNC_VSCFR;\n            }\n\n            if (ost->vsync_method == VSYNC_CFR && copy_ts) {\n                ost->vsync_method = VSYNC_VSCFR;\n            }\n        }\n        ost->is_cfr = (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR);\n\n        ost->avfilter = get_ost_filters(o, oc, ost);\n        if (!ost->avfilter)\n            exit_program(1);\n\n        ost->last_frame = av_frame_alloc();\n        if (!ost->last_frame)\n            exit_program(1);\n    }\n\n    if (ost->stream_copy)\n        check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_VIDEO);\n\n    return ost;\n}\n\nstatic OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    int n;\n    AVStream *st;\n    OutputStream *ost;\n    AVCodecContext *audio_enc;\n\n    ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);\n    st  = ost->st;\n\n    audio_enc = ost->enc_ctx;\n    audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;\n\n    MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);\n    MATCH_PER_STREAM_OPT(filters,        str, ost->filters,        oc, st);\n\n    if (!ost->stream_copy) {\n        int channels = 0;\n        char *layout = NULL;\n        char *sample_fmt = NULL;\n\n        MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st);\n        if (channels) {\n            audio_enc->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;\n            audio_enc->ch_layout.nb_channels = channels;\n        }\n\n        MATCH_PER_STREAM_OPT(audio_ch_layouts, str, layout, oc, st);\n        if (layout) {\n            if (av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) {\n#if FF_API_OLD_CHANNEL_LAYOUT\n                uint64_t mask;\n                AV_NOWARN_DEPRECATED({\n                mask = av_get_channel_layout(layout);\n                })\n                if (!mask) {\n#endif\n                    av_log(NULL, AV_LOG_FATAL, \"Unknown channel layout: %s\\n\", layout);\n                    exit_program(1);\n#if FF_API_OLD_CHANNEL_LAYOUT\n                }\n                av_log(NULL, AV_LOG_WARNING, \"Channel layout '%s' uses a deprecated syntax.\\n\",\n                       layout);\n                av_channel_layout_from_mask(&audio_enc->ch_layout, mask);\n#endif\n            }\n        }\n\n        MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);\n        if (sample_fmt &&\n            (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid sample format '%s'\\n\", sample_fmt);\n            exit_program(1);\n        }\n\n        MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);\n\n        MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);\n        ost->apad = av_strdup(ost->apad);\n\n        ost->avfilter = get_ost_filters(o, oc, ost);\n        if (!ost->avfilter)\n            exit_program(1);\n\n        /* check for channel mapping for this audio stream */\n        for (n = 0; n < o->nb_audio_channel_maps; n++) {\n            AudioChannelMap *map = &o->audio_channel_maps[n];\n            if ((map->ofile_idx   == -1 || ost->file_index == map->ofile_idx) &&\n                (map->ostream_idx == -1 || ost->st->index  == map->ostream_idx)) {\n                InputStream *ist;\n\n                if (map->channel_idx == -1) {\n                    ist = NULL;\n                } else if (ost->source_index < 0) {\n                    av_log(NULL, AV_LOG_FATAL, \"Cannot determine input stream for channel mapping %d.%d\\n\",\n                           ost->file_index, ost->st->index);\n                    continue;\n                } else {\n                    ist = input_streams[ost->source_index];\n                }\n\n                if (!ist || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) {\n                    if (av_reallocp_array(&ost->audio_channels_map,\n                                          ost->audio_channels_mapped + 1,\n                                          sizeof(*ost->audio_channels_map)\n                                          ) < 0 )\n                        exit_program(1);\n\n                    ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;\n                }\n            }\n        }\n    }\n\n    if (ost->stream_copy)\n        check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_AUDIO);\n\n    return ost;\n}\n\nstatic OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    OutputStream *ost;\n\n    ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);\n    if (!ost->stream_copy) {\n        av_log(NULL, AV_LOG_FATAL, \"Data stream encoding not supported yet (only streamcopy)\\n\");\n        exit_program(1);\n    }\n\n    return ost;\n}\n\nstatic OutputStream *new_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    OutputStream *ost;\n\n    ost = new_output_stream(o, oc, AVMEDIA_TYPE_UNKNOWN, source_index);\n    if (!ost->stream_copy) {\n        av_log(NULL, AV_LOG_FATAL, \"Unknown stream encoding not supported yet (only streamcopy)\\n\");\n        exit_program(1);\n    }\n\n    return ost;\n}\n\nstatic OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);\n    ost->stream_copy = 1;\n    ost->finished    = 1;\n    return ost;\n}\n\nstatic OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)\n{\n    AVStream *st;\n    OutputStream *ost;\n    AVCodecContext *subtitle_enc;\n\n    ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);\n    st  = ost->st;\n    subtitle_enc = ost->enc_ctx;\n\n    subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;\n\n    if (!ost->stream_copy) {\n        char *frame_size = NULL;\n\n        MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);\n        if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid frame size: %s.\\n\", frame_size);\n            exit_program(1);\n        }\n    }\n\n    return ost;\n}\n\n/* arg format is \"output-stream-index:streamid-value\". */\nstatic int opt_streamid(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    int idx;\n    char *p;\n    char idx_str[16];\n\n    av_strlcpy(idx_str, arg, sizeof(idx_str));\n    p = strchr(idx_str, ':');\n    if (!p) {\n        av_log(NULL, AV_LOG_FATAL,\n               \"Invalid value '%s' for option '%s', required syntax is 'index:value'\\n\",\n               arg, opt);\n        exit_program(1);\n    }\n    *p++ = '\\0';\n    idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);\n    o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);\n    o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);\n    return 0;\n}\n\nstatic int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *os,\n                         int copy_metadata)\n{\n    AVFormatContext *is = ifile->ctx;\n    AVChapter **tmp;\n    int i;\n\n    tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));\n    if (!tmp)\n        return AVERROR(ENOMEM);\n    os->chapters = tmp;\n\n    for (i = 0; i < is->nb_chapters; i++) {\n        AVChapter *in_ch = is->chapters[i], *out_ch;\n        int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;\n        int64_t ts_off   = av_rescale_q(start_time - ifile->ts_offset,\n                                       AV_TIME_BASE_Q, in_ch->time_base);\n        int64_t rt       = (ofile->recording_time == INT64_MAX) ? INT64_MAX :\n                           av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);\n\n\n        if (in_ch->end < ts_off)\n            continue;\n        if (rt != INT64_MAX && in_ch->start > rt + ts_off)\n            break;\n\n        out_ch = av_mallocz(sizeof(AVChapter));\n        if (!out_ch)\n            return AVERROR(ENOMEM);\n\n        out_ch->id        = in_ch->id;\n        out_ch->time_base = in_ch->time_base;\n        out_ch->start     = FFMAX(0,  in_ch->start - ts_off);\n        out_ch->end       = FFMIN(rt, in_ch->end   - ts_off);\n\n        if (copy_metadata)\n            av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);\n\n        os->chapters[os->nb_chapters++] = out_ch;\n    }\n    return 0;\n}\n\nstatic int set_dispositions(OutputFile *of, AVFormatContext *ctx)\n{\n    int nb_streams[AVMEDIA_TYPE_NB]   = { 0 };\n    int have_default[AVMEDIA_TYPE_NB] = { 0 };\n    int have_manual = 0;\n\n    // first, copy the input dispositions\n    for (int i = 0; i < ctx->nb_streams; i++) {\n        OutputStream *ost = output_streams[of->ost_index + i];\n\n        nb_streams[ost->st->codecpar->codec_type]++;\n\n        have_manual |= !!ost->disposition;\n\n        if (ost->source_index >= 0) {\n            ost->st->disposition = input_streams[ost->source_index]->st->disposition;\n\n            if (ost->st->disposition & AV_DISPOSITION_DEFAULT)\n                have_default[ost->st->codecpar->codec_type] = 1;\n        }\n    }\n\n    if (have_manual) {\n        // process manually set dispositions - they override the above copy\n        for (int i = 0; i < ctx->nb_streams; i++) {\n            OutputStream *ost = output_streams[of->ost_index + i];\n            int ret;\n\n            if (!ost->disposition)\n                continue;\n\n#if LIBAVFORMAT_VERSION_MAJOR >= 60\n            ret = av_opt_set(ost->st, \"disposition\", ost->disposition, 0);\n#else\n            {\n                const AVClass *class = av_stream_get_class();\n                const AVOption    *o = av_opt_find(&class, \"disposition\", NULL, 0, AV_OPT_SEARCH_FAKE_OBJ);\n\n                av_assert0(o);\n                ret = av_opt_eval_flags(&class, o, ost->disposition, &ost->st->disposition);\n            }\n#endif\n\n            if (ret < 0)\n                return ret;\n        }\n    } else {\n        // For each media type with more than one stream, find a suitable stream to\n        // mark as default, unless one is already marked default.\n        // \"Suitable\" means the first of that type, skipping attached pictures.\n        for (int i = 0; i < ctx->nb_streams; i++) {\n            OutputStream *ost = output_streams[of->ost_index + i];\n            enum AVMediaType type = ost->st->codecpar->codec_type;\n\n            if (nb_streams[type] < 2 || have_default[type] ||\n                ost->st->disposition & AV_DISPOSITION_ATTACHED_PIC)\n                continue;\n\n            ost->st->disposition |= AV_DISPOSITION_DEFAULT;\n            have_default[type] = 1;\n        }\n    }\n\n    return 0;\n}\n\nstatic void init_output_filter(OutputFilter *ofilter, OptionsContext *o,\n                               AVFormatContext *oc)\n{\n    OutputStream *ost;\n\n    switch (ofilter->type) {\n    case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;\n    case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;\n    default:\n        av_log(NULL, AV_LOG_FATAL, \"Only video and audio filters are supported \"\n               \"currently.\\n\");\n        exit_program(1);\n    }\n\n    ost->filter       = ofilter;\n\n    ofilter->ost      = ost;\n    ofilter->format   = -1;\n\n    if (ost->stream_copy) {\n        av_log(NULL, AV_LOG_ERROR, \"Streamcopy requested for output stream %d:%d, \"\n               \"which is fed from a complex filtergraph. Filtering and streamcopy \"\n               \"cannot be used together.\\n\", ost->file_index, ost->index);\n        exit_program(1);\n    }\n\n    if (ost->avfilter && (ost->filters || ost->filters_script)) {\n        const char *opt = ost->filters ? \"-vf/-af/-filter\" : \"-filter_script\";\n        av_log(NULL, AV_LOG_ERROR,\n               \"%s '%s' was specified through the %s option \"\n               \"for output stream %d:%d, which is fed from a complex filtergraph.\\n\"\n               \"%s and -filter_complex cannot be used together for the same stream.\\n\",\n               ost->filters ? \"Filtergraph\" : \"Filtergraph script\",\n               ost->filters ? ost->filters : ost->filters_script,\n               opt, ost->file_index, ost->index, opt);\n        exit_program(1);\n    }\n\n    avfilter_inout_free(&ofilter->out_tmp);\n}\n\nstatic int init_complex_filters(void)\n{\n    int i, ret = 0;\n\n    for (i = 0; i < nb_filtergraphs; i++) {\n        ret = init_complex_filtergraph(filtergraphs[i]);\n        if (ret < 0)\n            return ret;\n    }\n    return 0;\n}\n\nstatic void set_channel_layout(OutputFilter *f, OutputStream *ost)\n{\n    int i, err;\n\n    if (ost->enc_ctx->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {\n        /* Pass the layout through for all orders but UNSPEC */\n        err = av_channel_layout_copy(&f->ch_layout, &ost->enc_ctx->ch_layout);\n        if (err < 0)\n            exit_program(1);\n        return;\n    }\n\n    /* Requested layout is of order UNSPEC */\n    if (!ost->enc->ch_layouts) {\n        /* Use the default native layout for the requested amount of channels when the\n           encoder doesn't have a list of supported layouts */\n        av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels);\n        return;\n    }\n    /* Encoder has a list of supported layouts. Pick the first layout in it with the\n       same amount of channels as the requested layout */\n    for (i = 0; ost->enc->ch_layouts[i].nb_channels; i++) {\n        if (ost->enc->ch_layouts[i].nb_channels == ost->enc_ctx->ch_layout.nb_channels)\n            break;\n    }\n    if (ost->enc->ch_layouts[i].nb_channels) {\n        /* Use it if one is found */\n        err = av_channel_layout_copy(&f->ch_layout, &ost->enc->ch_layouts[i]);\n        if (err < 0)\n            exit_program(1);\n        return;\n    }\n    /* If no layout for the amount of channels requested was found, use the default\n       native layout for it. */\n    av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels);\n}\n\nstatic int open_output_file(OptionsContext *o, const char *filename)\n{\n    AVFormatContext *oc;\n    int i, j, err;\n    OutputFile *of;\n    OutputStream *ost;\n    InputStream  *ist;\n    AVDictionary *unused_opts = NULL;\n    const AVDictionaryEntry *e = NULL;\n\n    if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {\n        o->stop_time = INT64_MAX;\n        av_log(NULL, AV_LOG_WARNING, \"-t and -to cannot be used together; using -t.\\n\");\n    }\n\n    if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {\n        int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;\n        if (o->stop_time <= start_time) {\n            av_log(NULL, AV_LOG_ERROR, \"-to value smaller than -ss; aborting.\\n\");\n            exit_program(1);\n        } else {\n            o->recording_time = o->stop_time - start_time;\n        }\n    }\n\n    of = ALLOC_ARRAY_ELEM(output_files, nb_output_files);\n\n    of->index          = nb_output_files - 1;\n    of->ost_index      = nb_output_streams;\n    of->recording_time = o->recording_time;\n    of->start_time     = o->start_time;\n    of->limit_filesize = o->limit_filesize;\n    of->shortest       = o->shortest;\n    av_dict_copy(&of->opts, o->g->format_opts, 0);\n\n    if (!strcmp(filename, \"-\"))\n        filename = \"pipe:\";\n\n    err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);\n    if (!oc) {\n        print_error(filename, err);\n        exit_program(1);\n    }\n\n    of->ctx = oc;\n    of->format = oc->oformat;\n    if (o->recording_time != INT64_MAX)\n        oc->duration = o->recording_time;\n\n    oc->interrupt_callback = int_cb;\n\n    if (o->bitexact) {\n        oc->flags    |= AVFMT_FLAG_BITEXACT;\n    }\n\n    /* create streams for all unlabeled output pads */\n    for (i = 0; i < nb_filtergraphs; i++) {\n        FilterGraph *fg = filtergraphs[i];\n        for (j = 0; j < fg->nb_outputs; j++) {\n            OutputFilter *ofilter = fg->outputs[j];\n\n            if (!ofilter->out_tmp || ofilter->out_tmp->name)\n                continue;\n\n            switch (ofilter->type) {\n            case AVMEDIA_TYPE_VIDEO:    o->video_disable    = 1; break;\n            case AVMEDIA_TYPE_AUDIO:    o->audio_disable    = 1; break;\n            case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;\n            }\n            init_output_filter(ofilter, o, oc);\n        }\n    }\n\n    if (!o->nb_stream_maps) {\n        char *subtitle_codec_name = NULL;\n        /* pick the \"best\" stream of each type */\n\n        /* video: highest resolution */\n        if (!o->video_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO) != AV_CODEC_ID_NONE) {\n            int best_score = 0, idx = -1;\n            int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);\n            for (j = 0; j < nb_input_files; j++) {\n                InputFile *ifile = input_files[j];\n                int file_best_score = 0, file_best_idx = -1;\n                for (i = 0; i < ifile->nb_streams; i++) {\n                    int score;\n                    ist = input_streams[ifile->ist_index + i];\n                    score = ist->st->codecpar->width * ist->st->codecpar->height\n                               + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)\n                               + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT);\n                    if (ist->user_set_discard == AVDISCARD_ALL)\n                        continue;\n                    if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))\n                        score = 1;\n                    if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&\n                        score > file_best_score) {\n                        if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))\n                            continue;\n                        file_best_score = score;\n                        file_best_idx = ifile->ist_index + i;\n                    }\n                }\n                if (file_best_idx >= 0) {\n                    if((qcr == MKTAG('A', 'P', 'I', 'C')) || !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))\n                        file_best_score -= 5000000*!!(input_streams[file_best_idx]->st->disposition & AV_DISPOSITION_DEFAULT);\n                    if (file_best_score > best_score) {\n                        best_score = file_best_score;\n                        idx = file_best_idx;\n                    }\n               }\n            }\n            if (idx >= 0)\n                new_video_stream(o, oc, idx);\n        }\n\n        /* audio: most channels */\n        if (!o->audio_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_AUDIO) != AV_CODEC_ID_NONE) {\n            int best_score = 0, idx = -1;\n            for (j = 0; j < nb_input_files; j++) {\n                InputFile *ifile = input_files[j];\n                int file_best_score = 0, file_best_idx = -1;\n                for (i = 0; i < ifile->nb_streams; i++) {\n                    int score;\n                    ist = input_streams[ifile->ist_index + i];\n                    score = ist->st->codecpar->ch_layout.nb_channels\n                            + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)\n                            + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT);\n                    if (ist->user_set_discard == AVDISCARD_ALL)\n                        continue;\n                    if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&\n                        score > file_best_score) {\n                        file_best_score = score;\n                        file_best_idx = ifile->ist_index + i;\n                    }\n                }\n                if (file_best_idx >= 0) {\n                    file_best_score -= 5000000*!!(input_streams[file_best_idx]->st->disposition & AV_DISPOSITION_DEFAULT);\n                    if (file_best_score > best_score) {\n                        best_score = file_best_score;\n                        idx = file_best_idx;\n                    }\n               }\n            }\n            if (idx >= 0)\n                new_audio_stream(o, oc, idx);\n        }\n\n        /* subtitles: pick first */\n        MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, \"s\");\n        if (!o->subtitle_disable && (avcodec_find_encoder(oc->oformat->subtitle_codec) || subtitle_codec_name)) {\n            for (i = 0; i < nb_input_streams; i++)\n                if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {\n                    AVCodecDescriptor const *input_descriptor =\n                        avcodec_descriptor_get(input_streams[i]->st->codecpar->codec_id);\n                    AVCodecDescriptor const *output_descriptor = NULL;\n                    AVCodec const *output_codec =\n                        avcodec_find_encoder(oc->oformat->subtitle_codec);\n                    int input_props = 0, output_props = 0;\n                    if (input_streams[i]->user_set_discard == AVDISCARD_ALL)\n                        continue;\n                    if (output_codec)\n                        output_descriptor = avcodec_descriptor_get(output_codec->id);\n                    if (input_descriptor)\n                        input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);\n                    if (output_descriptor)\n                        output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);\n                    if (subtitle_codec_name ||\n                        input_props & output_props ||\n                        // Map dvb teletext which has neither property to any output subtitle encoder\n                        input_descriptor && output_descriptor &&\n                        (!input_descriptor->props ||\n                         !output_descriptor->props)) {\n                        new_subtitle_stream(o, oc, i);\n                        break;\n                    }\n                }\n        }\n        /* Data only if codec id match */\n        if (!o->data_disable ) {\n            enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA);\n            for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) {\n                if (input_streams[i]->user_set_discard == AVDISCARD_ALL)\n                    continue;\n                if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_DATA\n                    && input_streams[i]->st->codecpar->codec_id == codec_id )\n                    new_data_stream(o, oc, i);\n            }\n        }\n    } else {\n        for (i = 0; i < o->nb_stream_maps; i++) {\n            StreamMap *map = &o->stream_maps[i];\n\n            if (map->disabled)\n                continue;\n\n            if (map->linklabel) {\n                FilterGraph *fg;\n                OutputFilter *ofilter = NULL;\n                int j, k;\n\n                for (j = 0; j < nb_filtergraphs; j++) {\n                    fg = filtergraphs[j];\n                    for (k = 0; k < fg->nb_outputs; k++) {\n                        AVFilterInOut *out = fg->outputs[k]->out_tmp;\n                        if (out && !strcmp(out->name, map->linklabel)) {\n                            ofilter = fg->outputs[k];\n                            goto loop_end;\n                        }\n                    }\n                }\nloop_end:\n                if (!ofilter) {\n                    av_log(NULL, AV_LOG_FATAL, \"Output with label '%s' does not exist \"\n                           \"in any defined filter graph, or was already used elsewhere.\\n\", map->linklabel);\n                    exit_program(1);\n                }\n                init_output_filter(ofilter, o, oc);\n            } else {\n                int src_idx = input_files[map->file_index]->ist_index + map->stream_index;\n\n                ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];\n                if (ist->user_set_discard == AVDISCARD_ALL) {\n                    av_log(NULL, AV_LOG_FATAL, \"Stream #%d:%d is disabled and cannot be mapped.\\n\",\n                           map->file_index, map->stream_index);\n                    exit_program(1);\n                }\n                if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)\n                    continue;\n                if(o->   audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)\n                    continue;\n                if(o->   video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)\n                    continue;\n                if(o->    data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)\n                    continue;\n\n                ost = NULL;\n                switch (ist->st->codecpar->codec_type) {\n                case AVMEDIA_TYPE_VIDEO:      ost = new_video_stream     (o, oc, src_idx); break;\n                case AVMEDIA_TYPE_AUDIO:      ost = new_audio_stream     (o, oc, src_idx); break;\n                case AVMEDIA_TYPE_SUBTITLE:   ost = new_subtitle_stream  (o, oc, src_idx); break;\n                case AVMEDIA_TYPE_DATA:       ost = new_data_stream      (o, oc, src_idx); break;\n                case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;\n                case AVMEDIA_TYPE_UNKNOWN:\n                    if (copy_unknown_streams) {\n                        ost = new_unknown_stream   (o, oc, src_idx);\n                        break;\n                    }\n                default:\n                    av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,\n                           \"Cannot map stream #%d:%d - unsupported type.\\n\",\n                           map->file_index, map->stream_index);\n                    if (!ignore_unknown_streams) {\n                        av_log(NULL, AV_LOG_FATAL,\n                               \"If you want unsupported types ignored instead \"\n                               \"of failing, please use the -ignore_unknown option\\n\"\n                               \"If you want them copied, please use -copy_unknown\\n\");\n                        exit_program(1);\n                    }\n                }\n                if (ost)\n                    ost->sync_ist = input_streams[  input_files[map->sync_file_index]->ist_index\n                                                  + map->sync_stream_index];\n            }\n        }\n    }\n\n    /* handle attached files */\n    for (i = 0; i < o->nb_attachments; i++) {\n        AVIOContext *pb;\n        uint8_t *attachment;\n        const char *p;\n        int64_t len;\n\n        if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Could not open attachment file %s.\\n\",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        if ((len = avio_size(pb)) <= 0) {\n            av_log(NULL, AV_LOG_FATAL, \"Could not get size of the attachment %s.\\n\",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE ||\n            !(attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) {\n            av_log(NULL, AV_LOG_FATAL, \"Attachment %s too large.\\n\",\n                   o->attachments[i]);\n            exit_program(1);\n        }\n        avio_read(pb, attachment, len);\n        memset(attachment + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);\n\n        ost = new_attachment_stream(o, oc, -1);\n        ost->stream_copy               = 0;\n        ost->attachment_filename       = o->attachments[i];\n        ost->st->codecpar->extradata      = attachment;\n        ost->st->codecpar->extradata_size = len;\n\n        p = strrchr(o->attachments[i], '/');\n        av_dict_set(&ost->st->metadata, \"filename\", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);\n        avio_closep(&pb);\n    }\n\n    if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {\n        av_dump_format(oc, nb_output_files - 1, oc->url, 1);\n        av_log(NULL, AV_LOG_ERROR, \"Output file #%d does not contain any stream\\n\", nb_output_files - 1);\n        exit_program(1);\n    }\n\n    /* check if all codec options have been used */\n    unused_opts = strip_specifiers(o->g->codec_opts);\n    for (i = of->ost_index; i < nb_output_streams; i++) {\n        e = NULL;\n        while ((e = av_dict_get(output_streams[i]->encoder_opts, \"\", e,\n                                AV_DICT_IGNORE_SUFFIX)))\n            av_dict_set(&unused_opts, e->key, NULL, 0);\n    }\n\n    e = NULL;\n    while ((e = av_dict_get(unused_opts, \"\", e, AV_DICT_IGNORE_SUFFIX))) {\n        const AVClass *class = avcodec_get_class();\n        const AVOption *option = av_opt_find(&class, e->key, NULL, 0,\n                                             AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);\n        const AVClass *fclass = avformat_get_class();\n        const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0,\n                                              AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);\n        if (!option || foption)\n            continue;\n\n\n        if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {\n            av_log(NULL, AV_LOG_ERROR, \"Codec AVOption %s (%s) specified for \"\n                   \"output file #%d (%s) is not an encoding option.\\n\", e->key,\n                   option->help ? option->help : \"\", nb_output_files - 1,\n                   filename);\n            exit_program(1);\n        }\n\n        // gop_timecode is injected by generic code but not always used\n        if (!strcmp(e->key, \"gop_timecode\"))\n            continue;\n\n        av_log(NULL, AV_LOG_WARNING, \"Codec AVOption %s (%s) specified for \"\n               \"output file #%d (%s) has not been used for any stream. The most \"\n               \"likely reason is either wrong type (e.g. a video option with \"\n               \"no video streams) or that it is a private option of some encoder \"\n               \"which was not actually used for any stream.\\n\", e->key,\n               option->help ? option->help : \"\", nb_output_files - 1, filename);\n    }\n    av_dict_free(&unused_opts);\n\n    /* set the decoding_needed flags and create simple filtergraphs */\n    for (i = of->ost_index; i < nb_output_streams; i++) {\n        OutputStream *ost = output_streams[i];\n\n        if (ost->encoding_needed && ost->source_index >= 0) {\n            InputStream *ist = input_streams[ost->source_index];\n            ist->decoding_needed |= DECODING_FOR_OST;\n            ist->processing_needed = 1;\n\n            if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||\n                ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {\n                err = init_simple_filtergraph(ist, ost);\n                if (err < 0) {\n                    av_log(NULL, AV_LOG_ERROR,\n                           \"Error initializing a simple filtergraph between streams \"\n                           \"%d:%d->%d:%d\\n\", ist->file_index, ost->source_index,\n                           nb_output_files - 1, ost->st->index);\n                    exit_program(1);\n                }\n            }\n        } else if (ost->stream_copy && ost->source_index >= 0) {\n            InputStream *ist = input_streams[ost->source_index];\n            ist->processing_needed = 1;\n        }\n\n        /* set the filter output constraints */\n        if (ost->filter) {\n            OutputFilter *f = ost->filter;\n            switch (ost->enc_ctx->codec_type) {\n            case AVMEDIA_TYPE_VIDEO:\n                f->frame_rate = ost->frame_rate;\n                f->width      = ost->enc_ctx->width;\n                f->height     = ost->enc_ctx->height;\n                if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {\n                    f->format = ost->enc_ctx->pix_fmt;\n                } else {\n                    f->formats = ost->enc->pix_fmts;\n                }\n                break;\n            case AVMEDIA_TYPE_AUDIO:\n                if (ost->enc_ctx->sample_fmt != AV_SAMPLE_FMT_NONE) {\n                    f->format = ost->enc_ctx->sample_fmt;\n                } else {\n                    f->formats = ost->enc->sample_fmts;\n                }\n                if (ost->enc_ctx->sample_rate) {\n                    f->sample_rate = ost->enc_ctx->sample_rate;\n                } else {\n                    f->sample_rates = ost->enc->supported_samplerates;\n                }\n                if (ost->enc_ctx->ch_layout.nb_channels) {\n                    set_channel_layout(f, ost);\n                } else if (ost->enc->ch_layouts) {\n                    f->ch_layouts = ost->enc->ch_layouts;\n                }\n                break;\n            }\n        }\n    }\n\n    /* check filename in case of an image number is expected */\n    if (oc->oformat->flags & AVFMT_NEEDNUMBER) {\n        if (!av_filename_number_test(oc->url)) {\n            print_error(oc->url, AVERROR(EINVAL));\n            exit_program(1);\n        }\n    }\n\n    if (!(oc->oformat->flags & AVFMT_NOSTREAMS) && !input_stream_potentially_available) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"No input streams but output needs an input stream\\n\");\n        exit_program(1);\n    }\n\n    if (!(oc->oformat->flags & AVFMT_NOFILE)) {\n        /* test if it already exists to avoid losing precious files */\n        assert_file_overwrite(filename);\n\n        /* open the file */\n        if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,\n                              &oc->interrupt_callback,\n                              &of->opts)) < 0) {\n            print_error(filename, err);\n            exit_program(1);\n        }\n    } else if (strcmp(oc->oformat->name, \"image2\")==0 && !av_filename_number_test(filename))\n        assert_file_overwrite(filename);\n\n    if (o->mux_preload) {\n        av_dict_set_int(&of->opts, \"preload\", o->mux_preload*AV_TIME_BASE, 0);\n    }\n    oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);\n\n    /* copy metadata */\n    for (i = 0; i < o->nb_metadata_map; i++) {\n        char *p;\n        int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);\n\n        if (in_file_index >= nb_input_files) {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid input file index %d while processing metadata maps\\n\", in_file_index);\n            exit_program(1);\n        }\n        copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,\n                      in_file_index >= 0 ?\n                      input_files[in_file_index]->ctx : NULL, o);\n    }\n\n    /* copy chapters */\n    if (o->chapters_input_file >= nb_input_files) {\n        if (o->chapters_input_file == INT_MAX) {\n            /* copy chapters from the first input file that has them*/\n            o->chapters_input_file = -1;\n            for (i = 0; i < nb_input_files; i++)\n                if (input_files[i]->ctx->nb_chapters) {\n                    o->chapters_input_file = i;\n                    break;\n                }\n        } else {\n            av_log(NULL, AV_LOG_FATAL, \"Invalid input file index %d in chapter mapping.\\n\",\n                   o->chapters_input_file);\n            exit_program(1);\n        }\n    }\n    if (o->chapters_input_file >= 0)\n        copy_chapters(input_files[o->chapters_input_file], of, oc,\n                      !o->metadata_chapters_manual);\n\n    /* copy global metadata by default */\n    if (!o->metadata_global_manual && nb_input_files){\n        av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,\n                     AV_DICT_DONT_OVERWRITE);\n        if(o->recording_time != INT64_MAX)\n            av_dict_set(&oc->metadata, \"duration\", NULL, 0);\n        av_dict_set(&oc->metadata, \"creation_time\", NULL, 0);\n        av_dict_set(&oc->metadata, \"company_name\", NULL, 0);\n        av_dict_set(&oc->metadata, \"product_name\", NULL, 0);\n        av_dict_set(&oc->metadata, \"product_version\", NULL, 0);\n    }\n    if (!o->metadata_streams_manual)\n        for (i = of->ost_index; i < nb_output_streams; i++) {\n            InputStream *ist;\n            if (output_streams[i]->source_index < 0)         /* this is true e.g. for attached files */\n                continue;\n            ist = input_streams[output_streams[i]->source_index];\n            av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);\n            if (!output_streams[i]->stream_copy) {\n                av_dict_set(&output_streams[i]->st->metadata, \"encoder\", NULL, 0);\n            }\n        }\n\n    /* process manually set programs */\n    for (i = 0; i < o->nb_program; i++) {\n        const char *p = o->program[i].u.str;\n        int progid = i+1;\n        AVProgram *program;\n\n        while(*p) {\n            const char *p2 = av_get_token(&p, \":\");\n            const char *to_dealloc = p2;\n            char *key;\n            if (!p2)\n                break;\n\n            if(*p) p++;\n\n            key = av_get_token(&p2, \"=\");\n            if (!key || !*p2) {\n                av_freep(&to_dealloc);\n                av_freep(&key);\n                break;\n            }\n            p2++;\n\n            if (!strcmp(key, \"program_num\"))\n                progid = strtol(p2, NULL, 0);\n            av_freep(&to_dealloc);\n            av_freep(&key);\n        }\n\n        program = av_new_program(oc, progid);\n\n        p = o->program[i].u.str;\n        while(*p) {\n            const char *p2 = av_get_token(&p, \":\");\n            const char *to_dealloc = p2;\n            char *key;\n            if (!p2)\n                break;\n            if(*p) p++;\n\n            key = av_get_token(&p2, \"=\");\n            if (!key) {\n                av_log(NULL, AV_LOG_FATAL,\n                       \"No '=' character in program string %s.\\n\",\n                       p2);\n                exit_program(1);\n            }\n            if (!*p2)\n                exit_program(1);\n            p2++;\n\n            if (!strcmp(key, \"title\")) {\n                av_dict_set(&program->metadata, \"title\", p2, 0);\n            } else if (!strcmp(key, \"program_num\")) {\n            } else if (!strcmp(key, \"st\")) {\n                int st_num = strtol(p2, NULL, 0);\n                av_program_add_stream_index(oc, progid, st_num);\n            } else {\n                av_log(NULL, AV_LOG_FATAL, \"Unknown program key %s.\\n\", key);\n                exit_program(1);\n            }\n            av_freep(&to_dealloc);\n            av_freep(&key);\n        }\n    }\n\n    /* process manually set metadata */\n    for (i = 0; i < o->nb_metadata; i++) {\n        AVDictionary **m;\n        char type, *val;\n        const char *stream_spec;\n        int index = 0, j, ret = 0;\n\n        val = strchr(o->metadata[i].u.str, '=');\n        if (!val) {\n            av_log(NULL, AV_LOG_FATAL, \"No '=' character in metadata string %s.\\n\",\n                   o->metadata[i].u.str);\n            exit_program(1);\n        }\n        *val++ = 0;\n\n        parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);\n        if (type == 's') {\n            for (j = 0; j < oc->nb_streams; j++) {\n                ost = output_streams[nb_output_streams - oc->nb_streams + j];\n                if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {\n                    if (!strcmp(o->metadata[i].u.str, \"rotate\")) {\n                        char *tail;\n                        double theta = av_strtod(val, &tail);\n                        if (!*tail) {\n                            ost->rotate_overridden = 1;\n                            ost->rotate_override_value = theta;\n                        }\n                    } else {\n                        av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);\n                    }\n                } else if (ret < 0)\n                    exit_program(1);\n            }\n        }\n        else {\n            switch (type) {\n            case 'g':\n                m = &oc->metadata;\n                break;\n            case 'c':\n                if (index < 0 || index >= oc->nb_chapters) {\n                    av_log(NULL, AV_LOG_FATAL, \"Invalid chapter index %d in metadata specifier.\\n\", index);\n                    exit_program(1);\n                }\n                m = &oc->chapters[index]->metadata;\n                break;\n            case 'p':\n                if (index < 0 || index >= oc->nb_programs) {\n                    av_log(NULL, AV_LOG_FATAL, \"Invalid program index %d in metadata specifier.\\n\", index);\n                    exit_program(1);\n                }\n                m = &oc->programs[index]->metadata;\n                break;\n            default:\n                av_log(NULL, AV_LOG_FATAL, \"Invalid metadata specifier %s.\\n\", o->metadata[i].specifier);\n                exit_program(1);\n            }\n            av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);\n        }\n    }\n\n    err = set_dispositions(of, oc);\n    if (err < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error setting output stream dispositions\\n\");\n        exit_program(1);\n    }\n\n    return 0;\n}\n\nstatic int opt_target(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;\n    static const char *const frame_rates[] = { \"25\", \"30000/1001\", \"24000/1001\" };\n\n    if (!strncmp(arg, \"pal-\", 4)) {\n        norm = PAL;\n        arg += 4;\n    } else if (!strncmp(arg, \"ntsc-\", 5)) {\n        norm = NTSC;\n        arg += 5;\n    } else if (!strncmp(arg, \"film-\", 5)) {\n        norm = FILM;\n        arg += 5;\n    } else {\n        /* Try to determine PAL/NTSC by peeking in the input files */\n        if (nb_input_files) {\n            int i, j;\n            for (j = 0; j < nb_input_files; j++) {\n                for (i = 0; i < input_files[j]->nb_streams; i++) {\n                    AVStream *st = input_files[j]->ctx->streams[i];\n                    int64_t fr;\n                    if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)\n                        continue;\n                    fr = st->time_base.den * 1000LL / st->time_base.num;\n                    if (fr == 25000) {\n                        norm = PAL;\n                        break;\n                    } else if ((fr == 29970) || (fr == 23976)) {\n                        norm = NTSC;\n                        break;\n                    }\n                }\n                if (norm != UNKNOWN)\n                    break;\n            }\n        }\n        if (norm != UNKNOWN)\n            av_log(NULL, AV_LOG_INFO, \"Assuming %s for target.\\n\", norm == PAL ? \"PAL\" : \"NTSC\");\n    }\n\n    if (norm == UNKNOWN) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not determine norm (PAL/NTSC/NTSC-Film) for target.\\n\");\n        av_log(NULL, AV_LOG_FATAL, \"Please prefix target with \\\"pal-\\\", \\\"ntsc-\\\" or \\\"film-\\\",\\n\");\n        av_log(NULL, AV_LOG_FATAL, \"or set a framerate with \\\"-r xxx\\\".\\n\");\n        exit_program(1);\n    }\n\n    if (!strcmp(arg, \"vcd\")) {\n        opt_video_codec(o, \"c:v\", \"mpeg1video\");\n        opt_audio_codec(o, \"c:a\", \"mp2\");\n        parse_option(o, \"f\", \"vcd\", options);\n\n        parse_option(o, \"s\", norm == PAL ? \"352x288\" : \"352x240\", options);\n        parse_option(o, \"r\", frame_rates[norm], options);\n        opt_default(NULL, \"g\", norm == PAL ? \"15\" : \"18\");\n\n        opt_default(NULL, \"b:v\", \"1150000\");\n        opt_default(NULL, \"maxrate:v\", \"1150000\");\n        opt_default(NULL, \"minrate:v\", \"1150000\");\n        opt_default(NULL, \"bufsize:v\", \"327680\"); // 40*1024*8;\n\n        opt_default(NULL, \"b:a\", \"224000\");\n        parse_option(o, \"ar\", \"44100\", options);\n        parse_option(o, \"ac\", \"2\", options);\n\n        opt_default(NULL, \"packetsize\", \"2324\");\n        opt_default(NULL, \"muxrate\", \"1411200\"); // 2352 * 75 * 8;\n\n        /* We have to offset the PTS, so that it is consistent with the SCR.\n           SCR starts at 36000, but the first two packs contain only padding\n           and the first pack from the other stream, respectively, may also have\n           been written before.\n           So the real data starts at SCR 36000+3*1200. */\n        o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44\n    } else if (!strcmp(arg, \"svcd\")) {\n\n        opt_video_codec(o, \"c:v\", \"mpeg2video\");\n        opt_audio_codec(o, \"c:a\", \"mp2\");\n        parse_option(o, \"f\", \"svcd\", options);\n\n        parse_option(o, \"s\", norm == PAL ? \"480x576\" : \"480x480\", options);\n        parse_option(o, \"r\", frame_rates[norm], options);\n        parse_option(o, \"pix_fmt\", \"yuv420p\", options);\n        opt_default(NULL, \"g\", norm == PAL ? \"15\" : \"18\");\n\n        opt_default(NULL, \"b:v\", \"2040000\");\n        opt_default(NULL, \"maxrate:v\", \"2516000\");\n        opt_default(NULL, \"minrate:v\", \"0\"); // 1145000;\n        opt_default(NULL, \"bufsize:v\", \"1835008\"); // 224*1024*8;\n        opt_default(NULL, \"scan_offset\", \"1\");\n\n        opt_default(NULL, \"b:a\", \"224000\");\n        parse_option(o, \"ar\", \"44100\", options);\n\n        opt_default(NULL, \"packetsize\", \"2324\");\n\n    } else if (!strcmp(arg, \"dvd\")) {\n\n        opt_video_codec(o, \"c:v\", \"mpeg2video\");\n        opt_audio_codec(o, \"c:a\", \"ac3\");\n        parse_option(o, \"f\", \"dvd\", options);\n\n        parse_option(o, \"s\", norm == PAL ? \"720x576\" : \"720x480\", options);\n        parse_option(o, \"r\", frame_rates[norm], options);\n        parse_option(o, \"pix_fmt\", \"yuv420p\", options);\n        opt_default(NULL, \"g\", norm == PAL ? \"15\" : \"18\");\n\n        opt_default(NULL, \"b:v\", \"6000000\");\n        opt_default(NULL, \"maxrate:v\", \"9000000\");\n        opt_default(NULL, \"minrate:v\", \"0\"); // 1500000;\n        opt_default(NULL, \"bufsize:v\", \"1835008\"); // 224*1024*8;\n\n        opt_default(NULL, \"packetsize\", \"2048\");  // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.\n        opt_default(NULL, \"muxrate\", \"10080000\"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8\n\n        opt_default(NULL, \"b:a\", \"448000\");\n        parse_option(o, \"ar\", \"48000\", options);\n\n    } else if (!strncmp(arg, \"dv\", 2)) {\n\n        parse_option(o, \"f\", \"dv\", options);\n\n        parse_option(o, \"s\", norm == PAL ? \"720x576\" : \"720x480\", options);\n        parse_option(o, \"pix_fmt\", !strncmp(arg, \"dv50\", 4) ? \"yuv422p\" :\n                          norm == PAL ? \"yuv420p\" : \"yuv411p\", options);\n        parse_option(o, \"r\", frame_rates[norm], options);\n\n        parse_option(o, \"ar\", \"48000\", options);\n        parse_option(o, \"ac\", \"2\", options);\n\n    } else {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown target: %s\\n\", arg);\n        return AVERROR(EINVAL);\n    }\n\n    av_dict_copy(&o->g->codec_opts,  codec_opts, AV_DICT_DONT_OVERWRITE);\n    av_dict_copy(&o->g->format_opts, format_opts, AV_DICT_DONT_OVERWRITE);\n\n    return 0;\n}\n\nstatic int opt_vstats_file(void *optctx, const char *opt, const char *arg)\n{\n    av_free (vstats_filename);\n    vstats_filename = av_strdup (arg);\n    return 0;\n}\n\nstatic int opt_vstats(void *optctx, const char *opt, const char *arg)\n{\n    char filename[40];\n    time_t today2 = time(NULL);\n    struct tm *today = localtime(&today2);\n\n    if (!today) { // maybe tomorrow\n        av_log(NULL, AV_LOG_FATAL, \"Unable to get current time: %s\\n\", strerror(errno));\n        exit_program(1);\n    }\n\n    snprintf(filename, sizeof(filename), \"vstats_%02d%02d%02d.log\", today->tm_hour, today->tm_min,\n             today->tm_sec);\n    return opt_vstats_file(NULL, opt, filename);\n}\n\nstatic int opt_video_frames(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"frames:v\", arg, options);\n}\n\nstatic int opt_audio_frames(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"frames:a\", arg, options);\n}\n\nstatic int opt_data_frames(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"frames:d\", arg, options);\n}\n\nstatic int opt_default_new(OptionsContext *o, const char *opt, const char *arg)\n{\n    int ret;\n    AVDictionary *cbak = codec_opts;\n    AVDictionary *fbak = format_opts;\n    codec_opts = NULL;\n    format_opts = NULL;\n\n    ret = opt_default(NULL, opt, arg);\n\n    av_dict_copy(&o->g->codec_opts , codec_opts, 0);\n    av_dict_copy(&o->g->format_opts, format_opts, 0);\n    av_dict_free(&codec_opts);\n    av_dict_free(&format_opts);\n    codec_opts = cbak;\n    format_opts = fbak;\n\n    return ret;\n}\n\nstatic int opt_preset(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    FILE *f=NULL;\n    char filename[1000], line[1000], tmp_line[1000];\n    const char *codec_name = NULL;\n\n    tmp_line[0] = *opt;\n    tmp_line[1] = 0;\n    MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);\n\n    if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {\n        if(!strncmp(arg, \"libx264-lossless\", strlen(\"libx264-lossless\"))){\n            av_log(NULL, AV_LOG_FATAL, \"Please use -preset <speed> -qp 0\\n\");\n        }else\n            av_log(NULL, AV_LOG_FATAL, \"File for preset '%s' not found\\n\", arg);\n        exit_program(1);\n    }\n\n    while (fgets(line, sizeof(line), f)) {\n        char *key = tmp_line, *value, *endptr;\n\n        if (strcspn(line, \"#\\n\\r\") == 0)\n            continue;\n        av_strlcpy(tmp_line, line, sizeof(tmp_line));\n        if (!av_strtok(key,   \"=\",    &value) ||\n            !av_strtok(value, \"\\r\\n\", &endptr)) {\n            av_log(NULL, AV_LOG_FATAL, \"%s: Invalid syntax: '%s'\\n\", filename, line);\n            exit_program(1);\n        }\n        av_log(NULL, AV_LOG_DEBUG, \"ffpreset[%s]: set '%s' = '%s'\\n\", filename, key, value);\n\n        if      (!strcmp(key, \"acodec\")) opt_audio_codec   (o, key, value);\n        else if (!strcmp(key, \"vcodec\")) opt_video_codec   (o, key, value);\n        else if (!strcmp(key, \"scodec\")) opt_subtitle_codec(o, key, value);\n        else if (!strcmp(key, \"dcodec\")) opt_data_codec    (o, key, value);\n        else if (opt_default_new(o, key, value) < 0) {\n            av_log(NULL, AV_LOG_FATAL, \"%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\\n\",\n                   filename, line, key, value);\n            exit_program(1);\n        }\n    }\n\n    fclose(f);\n\n    return 0;\n}\n\nstatic int opt_old2new(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    int ret;\n    char *s = av_asprintf(\"%s:%c\", opt + 1, *opt);\n    if (!s)\n        return AVERROR(ENOMEM);\n    ret = parse_option(o, s, arg, options);\n    av_free(s);\n    return ret;\n}\n\nstatic int opt_bitrate(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n\n    if(!strcmp(opt, \"ab\")){\n        av_dict_set(&o->g->codec_opts, \"b:a\", arg, 0);\n        return 0;\n    } else if(!strcmp(opt, \"b\")){\n        av_log(NULL, AV_LOG_WARNING, \"Please use -b:a or -b:v, -b is ambiguous\\n\");\n        av_dict_set(&o->g->codec_opts, \"b:v\", arg, 0);\n        return 0;\n    }\n    av_dict_set(&o->g->codec_opts, opt, arg, 0);\n    return 0;\n}\n\nstatic int opt_qscale(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    char *s;\n    int ret;\n    if(!strcmp(opt, \"qscale\")){\n        av_log(NULL, AV_LOG_WARNING, \"Please use -q:a or -q:v, -qscale is ambiguous\\n\");\n        return parse_option(o, \"q:v\", arg, options);\n    }\n    s = av_asprintf(\"q%s\", opt + 6);\n    if (!s)\n        return AVERROR(ENOMEM);\n    ret = parse_option(o, s, arg, options);\n    av_free(s);\n    return ret;\n}\n\nstatic int opt_profile(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    if(!strcmp(opt, \"profile\")){\n        av_log(NULL, AV_LOG_WARNING, \"Please use -profile:a or -profile:v, -profile is ambiguous\\n\");\n        av_dict_set(&o->g->codec_opts, \"profile:v\", arg, 0);\n        return 0;\n    }\n    av_dict_set(&o->g->codec_opts, opt, arg, 0);\n    return 0;\n}\n\nstatic int opt_video_filters(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"filter:v\", arg, options);\n}\n\nstatic int opt_audio_filters(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"filter:a\", arg, options);\n}\n\nstatic int opt_vsync(void *optctx, const char *opt, const char *arg)\n{\n    av_log(NULL, AV_LOG_WARNING, \"-vsync is deprecated. Use -fps_mode\\n\");\n    parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);\n    return 0;\n}\n\nstatic int opt_timecode(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    int ret;\n    char *tcr = av_asprintf(\"timecode=%s\", arg);\n    if (!tcr)\n        return AVERROR(ENOMEM);\n    ret = parse_option(o, \"metadata:g\", tcr, options);\n    if (ret >= 0)\n        ret = av_dict_set(&o->g->codec_opts, \"gop_timecode\", arg, 0);\n    av_free(tcr);\n    return ret;\n}\n\nstatic int opt_audio_qscale(void *optctx, const char *opt, const char *arg)\n{\n    OptionsContext *o = optctx;\n    return parse_option(o, \"q:a\", arg, options);\n}\n\nstatic int opt_filter_complex(void *optctx, const char *opt, const char *arg)\n{\n    FilterGraph *fg = ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);\n\n    fg->index      = nb_filtergraphs - 1;\n    fg->graph_desc = av_strdup(arg);\n    if (!fg->graph_desc)\n        return AVERROR(ENOMEM);\n\n    input_stream_potentially_available = 1;\n\n    return 0;\n}\n\nstatic int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)\n{\n    FilterGraph *fg;\n    char *graph_desc = read_file(arg);\n    if (!graph_desc)\n        return AVERROR(EINVAL);\n\n    fg = ALLOC_ARRAY_ELEM(filtergraphs, nb_filtergraphs);\n    fg->index      = nb_filtergraphs - 1;\n    fg->graph_desc = graph_desc;\n\n    input_stream_potentially_available = 1;\n\n    return 0;\n}\n\nvoid show_help_default(const char *opt, const char *arg)\n{\n    /* per-file options have at least one of those set */\n    const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;\n    int show_advanced = 0, show_avoptions = 0;\n\n    if (opt && *opt) {\n        if (!strcmp(opt, \"long\"))\n            show_advanced = 1;\n        else if (!strcmp(opt, \"full\"))\n            show_advanced = show_avoptions = 1;\n        else\n            av_log(NULL, AV_LOG_ERROR, \"Unknown help option '%s'.\\n\", opt);\n    }\n\n    show_usage();\n\n    printf(\"Getting help:\\n\"\n           \"    -h      -- print basic options\\n\"\n           \"    -h long -- print more options\\n\"\n           \"    -h full -- print all options (including all format and codec specific options, very long)\\n\"\n           \"    -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf/protocol\\n\"\n           \"    See man %s for detailed description of the options.\\n\"\n           \"\\n\", program_name);\n\n    show_help_options(options, \"Print help / information / capabilities:\",\n                      OPT_EXIT, 0, 0);\n\n    show_help_options(options, \"Global options (affect whole program \"\n                      \"instead of just one file):\",\n                      0, per_file | OPT_EXIT | OPT_EXPERT, 0);\n    if (show_advanced)\n        show_help_options(options, \"Advanced global options:\", OPT_EXPERT,\n                          per_file | OPT_EXIT, 0);\n\n    show_help_options(options, \"Per-file main options:\", 0,\n                      OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |\n                      OPT_EXIT, per_file);\n    if (show_advanced)\n        show_help_options(options, \"Advanced per-file options:\",\n                          OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);\n\n    show_help_options(options, \"Video options:\",\n                      OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);\n    if (show_advanced)\n        show_help_options(options, \"Advanced Video options:\",\n                          OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);\n\n    show_help_options(options, \"Audio options:\",\n                      OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);\n    if (show_advanced)\n        show_help_options(options, \"Advanced Audio options:\",\n                          OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);\n    show_help_options(options, \"Subtitle options:\",\n                      OPT_SUBTITLE, 0, 0);\n    printf(\"\\n\");\n\n    if (show_avoptions) {\n        int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;\n        show_help_children(avcodec_get_class(), flags);\n        show_help_children(avformat_get_class(), flags);\n#if CONFIG_SWSCALE\n        show_help_children(sws_get_class(), flags);\n#endif\n#if CONFIG_SWRESAMPLE\n        show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);\n#endif\n        show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);\n        show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM);\n    }\n}\n\nvoid show_usage(void)\n{\n    av_log(NULL, AV_LOG_INFO, \"Hyper fast Audio and Video encoder\\n\");\n    av_log(NULL, AV_LOG_INFO, \"usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\\n\", program_name);\n    av_log(NULL, AV_LOG_INFO, \"\\n\");\n}\n\nenum OptGroup {\n    GROUP_OUTFILE,\n    GROUP_INFILE,\n};\n\nstatic const OptionGroupDef groups[] = {\n    [GROUP_OUTFILE] = { \"output url\",  NULL, OPT_OUTPUT },\n    [GROUP_INFILE]  = { \"input url\",   \"i\",  OPT_INPUT },\n};\n\nstatic int open_files(OptionGroupList *l, const char *inout,\n                      int (*open_file)(OptionsContext*, const char*))\n{\n    int i, ret;\n\n    for (i = 0; i < l->nb_groups; i++) {\n        OptionGroup *g = &l->groups[i];\n        OptionsContext o;\n\n        init_options(&o);\n        o.g = g;\n\n        ret = parse_optgroup(&o, g);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error parsing options for %s file \"\n                   \"%s.\\n\", inout, g->arg);\n            uninit_options(&o);\n            return ret;\n        }\n\n        av_log(NULL, AV_LOG_DEBUG, \"Opening an %s file: %s.\\n\", inout, g->arg);\n        ret = open_file(&o, g->arg);\n        uninit_options(&o);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error opening %s file %s.\\n\",\n                   inout, g->arg);\n            return ret;\n        }\n        av_log(NULL, AV_LOG_DEBUG, \"Successfully opened the file.\\n\");\n    }\n\n    return 0;\n}\n\nint ffmpeg_parse_options(int argc, char **argv)\n{\n    OptionParseContext octx;\n    uint8_t error[128];\n    int ret;\n\n    memset(&octx, 0, sizeof(octx));\n\n    /* split the commandline into an internal representation */\n    ret = split_commandline(&octx, argc, argv, options, groups,\n                            FF_ARRAY_ELEMS(groups));\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error splitting the argument list: \");\n        goto fail;\n    }\n\n    /* apply global options */\n    ret = parse_optgroup(NULL, &octx.global_opts);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error parsing global options: \");\n        goto fail;\n    }\n\n    /* configure terminal and setup signal handlers */\n    term_init();\n\n    /* open input files */\n    ret = open_files(&octx.groups[GROUP_INFILE], \"input\", open_input_file);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error opening input files: \");\n        goto fail;\n    }\n\n    apply_sync_offsets();\n\n    /* create the complex filtergraphs */\n    ret = init_complex_filters();\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error initializing complex filters.\\n\");\n        goto fail;\n    }\n\n    /* open output files */\n    ret = open_files(&octx.groups[GROUP_OUTFILE], \"output\", open_output_file);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Error opening output files: \");\n        goto fail;\n    }\n\n    check_filter_outputs();\n\nfail:\n    uninit_parse_context(&octx);\n    if (ret < 0) {\n        av_strerror(ret, error, sizeof(error));\n        av_log(NULL, AV_LOG_FATAL, \"%s\\n\", error);\n    }\n    return ret;\n}\n\nstatic int opt_progress(void *optctx, const char *opt, const char *arg)\n{\n    AVIOContext *avio = NULL;\n    int ret;\n\n    if (!strcmp(arg, \"-\"))\n        arg = \"pipe:\";\n    ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Failed to open progress URL \\\"%s\\\": %s\\n\",\n               arg, av_err2str(ret));\n        return ret;\n    }\n    progress_avio = avio;\n    return 0;\n}\n\nint opt_timelimit(void *optctx, const char *opt, const char *arg)\n{\n#if HAVE_SETRLIMIT\n    int lim = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);\n    struct rlimit rl = { lim, lim + 1 };\n    if (setrlimit(RLIMIT_CPU, &rl))\n        perror(\"setrlimit\");\n#else\n    av_log(NULL, AV_LOG_WARNING, \"-%s not implemented on this OS\\n\", opt);\n#endif\n    return 0;\n}\n\n#define OFFSET(x) offsetof(OptionsContext, x)\nconst OptionDef options[] = {\n    /* main options */\n    CMDUTILS_COMMON_OPTIONS\n    { \"f\",              HAS_ARG | OPT_STRING | OPT_OFFSET |\n                        OPT_INPUT | OPT_OUTPUT,                      { .off       = OFFSET(format) },\n        \"force format\", \"fmt\" },\n    { \"y\",              OPT_BOOL,                                    {              &file_overwrite },\n        \"overwrite output files\" },\n    { \"n\",              OPT_BOOL,                                    {              &no_file_overwrite },\n        \"never overwrite output files\" },\n    { \"ignore_unknown\", OPT_BOOL,                                    {              &ignore_unknown_streams },\n        \"Ignore unknown stream types\" },\n    { \"copy_unknown\",   OPT_BOOL | OPT_EXPERT,                       {              &copy_unknown_streams },\n        \"Copy unknown stream types\" },\n    { \"recast_media\",   OPT_BOOL | OPT_EXPERT,                       {              &recast_media },\n        \"allow recasting stream type in order to force a decoder of different media type\" },\n    { \"c\",              HAS_ARG | OPT_STRING | OPT_SPEC |\n                        OPT_INPUT | OPT_OUTPUT,                      { .off       = OFFSET(codec_names) },\n        \"codec name\", \"codec\" },\n    { \"codec\",          HAS_ARG | OPT_STRING | OPT_SPEC |\n                        OPT_INPUT | OPT_OUTPUT,                      { .off       = OFFSET(codec_names) },\n        \"codec name\", \"codec\" },\n    { \"pre\",            HAS_ARG | OPT_STRING | OPT_SPEC |\n                        OPT_OUTPUT,                                  { .off       = OFFSET(presets) },\n        \"preset name\", \"preset\" },\n    { \"map\",            HAS_ARG | OPT_EXPERT | OPT_PERFILE |\n                        OPT_OUTPUT,                                  { .func_arg = opt_map },\n        \"set input stream mapping\",\n        \"[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]\" },\n    { \"map_channel\",    HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_map_channel },\n        \"map an audio channel from one stream to another\", \"file.stream.channel[:syncfile.syncstream]\" },\n    { \"map_metadata\",   HAS_ARG | OPT_STRING | OPT_SPEC |\n                        OPT_OUTPUT,                                  { .off       = OFFSET(metadata_map) },\n        \"set metadata information of outfile from infile\",\n        \"outfile[,metadata]:infile[,metadata]\" },\n    { \"map_chapters\",   HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |\n                        OPT_OUTPUT,                                  { .off = OFFSET(chapters_input_file) },\n        \"set chapters mapping\", \"input_file_index\" },\n    { \"t\",              HAS_ARG | OPT_TIME | OPT_OFFSET |\n                        OPT_INPUT | OPT_OUTPUT,                      { .off = OFFSET(recording_time) },\n        \"record or transcode \\\"duration\\\" seconds of audio/video\",\n        \"duration\" },\n    { \"to\",             HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,  { .off = OFFSET(stop_time) },\n        \"record or transcode stop time\", \"time_stop\" },\n    { \"fs\",             HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },\n        \"set the limit file size in bytes\", \"limit_size\" },\n    { \"ss\",             HAS_ARG | OPT_TIME | OPT_OFFSET |\n                        OPT_INPUT | OPT_OUTPUT,                      { .off = OFFSET(start_time) },\n        \"set the start time offset\", \"time_off\" },\n    { \"sseof\",          HAS_ARG | OPT_TIME | OPT_OFFSET |\n                        OPT_INPUT,                                   { .off = OFFSET(start_time_eof) },\n        \"set the start time offset relative to EOF\", \"time_off\" },\n    { \"seek_timestamp\", HAS_ARG | OPT_INT | OPT_OFFSET |\n                        OPT_INPUT,                                   { .off = OFFSET(seek_timestamp) },\n        \"enable/disable seeking by timestamp with -ss\" },\n    { \"accurate_seek\",  OPT_BOOL | OPT_OFFSET | OPT_EXPERT |\n                        OPT_INPUT,                                   { .off = OFFSET(accurate_seek) },\n        \"enable/disable accurate seeking with -ss\" },\n    { \"isync\",          HAS_ARG | OPT_INT | OPT_OFFSET |\n                        OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(input_sync_ref) },\n        \"Indicate the input index for sync reference\", \"sync ref\" },\n    { \"itsoffset\",      HAS_ARG | OPT_TIME | OPT_OFFSET |\n                        OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(input_ts_offset) },\n        \"set the input ts offset\", \"time_off\" },\n    { \"itsscale\",       HAS_ARG | OPT_DOUBLE | OPT_SPEC |\n                        OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(ts_scale) },\n        \"set the input ts scale\", \"scale\" },\n    { \"timestamp\",      HAS_ARG | OPT_PERFILE | OPT_OUTPUT,          { .func_arg = opt_recording_timestamp },\n        \"set the recording timestamp ('now' to set the current time)\", \"time\" },\n    { \"metadata\",       HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(metadata) },\n        \"add metadata\", \"string=string\" },\n    { \"program\",        HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(program) },\n        \"add program with specified streams\", \"title=string:st=number...\" },\n    { \"dframes\",        HAS_ARG | OPT_PERFILE | OPT_EXPERT |\n                        OPT_OUTPUT,                                  { .func_arg = opt_data_frames },\n        \"set the number of data frames to output\", \"number\" },\n    { \"benchmark\",      OPT_BOOL | OPT_EXPERT,                       { &do_benchmark },\n        \"add timings for benchmarking\" },\n    { \"benchmark_all\",  OPT_BOOL | OPT_EXPERT,                       { &do_benchmark_all },\n      \"add timings for each task\" },\n    { \"progress\",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_progress },\n      \"write program-readable progress information\", \"url\" },\n    { \"stdin\",          OPT_BOOL | OPT_EXPERT,                       { &stdin_interaction },\n      \"enable or disable interaction on standard input\" },\n    { \"timelimit\",      HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_timelimit },\n        \"set max runtime in seconds in CPU user time\", \"limit\" },\n    { \"dump\",           OPT_BOOL | OPT_EXPERT,                       { &do_pkt_dump },\n        \"dump each input packet\" },\n    { \"hex\",            OPT_BOOL | OPT_EXPERT,                       { &do_hex_dump },\n        \"when dumping packets, also dump the payload\" },\n    { \"re\",             OPT_BOOL | OPT_EXPERT | OPT_OFFSET |\n                        OPT_INPUT,                                   { .off = OFFSET(rate_emu) },\n        \"read input at native frame rate; equivalent to -readrate 1\", \"\" },\n    { \"readrate\",       HAS_ARG | OPT_FLOAT | OPT_OFFSET |\n                        OPT_EXPERT | OPT_INPUT,                      { .off = OFFSET(readrate) },\n        \"read input at specified rate\", \"speed\" },\n    { \"target\",         HAS_ARG | OPT_PERFILE | OPT_OUTPUT,          { .func_arg = opt_target },\n        \"specify target file type (\\\"vcd\\\", \\\"svcd\\\", \\\"dvd\\\", \\\"dv\\\" or \\\"dv50\\\" \"\n        \"with optional prefixes \\\"pal-\\\", \\\"ntsc-\\\" or \\\"film-\\\")\", \"type\" },\n    { \"vsync\",          HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_vsync },\n        \"set video sync method globally; deprecated, use -fps_mode\", \"\" },\n    { \"frame_drop_threshold\", HAS_ARG | OPT_FLOAT | OPT_EXPERT,      { &frame_drop_threshold },\n        \"frame drop threshold\", \"\" },\n    { \"async\",          HAS_ARG | OPT_INT | OPT_EXPERT,              { &audio_sync_method },\n        \"audio sync method\", \"\" },\n    { \"adrift_threshold\", HAS_ARG | OPT_FLOAT | OPT_EXPERT,          { &audio_drift_threshold },\n        \"audio drift threshold\", \"threshold\" },\n    { \"copyts\",         OPT_BOOL | OPT_EXPERT,                       { &copy_ts },\n        \"copy timestamps\" },\n    { \"start_at_zero\",  OPT_BOOL | OPT_EXPERT,                       { &start_at_zero },\n        \"shift input timestamps to start at 0 when using copyts\" },\n    { \"copytb\",         HAS_ARG | OPT_INT | OPT_EXPERT,              { &copy_tb },\n        \"copy input stream time base when stream copying\", \"mode\" },\n    { \"shortest\",       OPT_BOOL | OPT_EXPERT | OPT_OFFSET |\n                        OPT_OUTPUT,                                  { .off = OFFSET(shortest) },\n        \"finish encoding within shortest input\" },\n    { \"bitexact\",       OPT_BOOL | OPT_EXPERT | OPT_OFFSET |\n                        OPT_OUTPUT | OPT_INPUT,                      { .off = OFFSET(bitexact) },\n        \"bitexact mode\" },\n    { \"apad\",           OPT_STRING | HAS_ARG | OPT_SPEC |\n                        OPT_OUTPUT,                                  { .off = OFFSET(apad) },\n        \"audio pad\", \"\" },\n    { \"dts_delta_threshold\", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_delta_threshold },\n        \"timestamp discontinuity delta threshold\", \"threshold\" },\n    { \"dts_error_threshold\", HAS_ARG | OPT_FLOAT | OPT_EXPERT,       { &dts_error_threshold },\n        \"timestamp error delta threshold\", \"threshold\" },\n    { \"xerror\",         OPT_BOOL | OPT_EXPERT,                       { &exit_on_error },\n        \"exit on error\", \"error\" },\n    { \"abort_on\",       HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_abort_on },\n        \"abort on the specified condition flags\", \"flags\" },\n    { \"copyinkf\",       OPT_BOOL | OPT_EXPERT | OPT_SPEC |\n                        OPT_OUTPUT,                                  { .off = OFFSET(copy_initial_nonkeyframes) },\n        \"copy initial non-keyframes\" },\n    { \"copypriorss\",    OPT_INT | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT,   { .off = OFFSET(copy_prior_start) },\n        \"copy or discard frames before start time\" },\n    { \"frames\",         OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) },\n        \"set the number of frames to output\", \"number\" },\n    { \"tag\",            OPT_STRING | HAS_ARG | OPT_SPEC |\n                        OPT_EXPERT | OPT_OUTPUT | OPT_INPUT,         { .off = OFFSET(codec_tags) },\n        \"force codec tag/fourcc\", \"fourcc/tag\" },\n    { \"q\",              HAS_ARG | OPT_EXPERT | OPT_DOUBLE |\n                        OPT_SPEC | OPT_OUTPUT,                       { .off = OFFSET(qscale) },\n        \"use fixed quality scale (VBR)\", \"q\" },\n    { \"qscale\",         HAS_ARG | OPT_EXPERT | OPT_PERFILE |\n                        OPT_OUTPUT,                                  { .func_arg = opt_qscale },\n        \"use fixed quality scale (VBR)\", \"q\" },\n    { \"profile\",        HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_profile },\n        \"set profile\", \"profile\" },\n    { \"filter\",         HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },\n        \"set stream filtergraph\", \"filter_graph\" },\n    { \"filter_threads\", HAS_ARG,                                     { .func_arg = opt_filter_threads },\n        \"number of non-complex filter threads\" },\n    { \"filter_script\",  HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },\n        \"read stream filtergraph description from a file\", \"filename\" },\n    { \"reinit_filter\",  HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT,    { .off = OFFSET(reinit_filters) },\n        \"reinit filtergraph on input parameter changes\", \"\" },\n    { \"filter_complex\", HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_filter_complex },\n        \"create a complex filtergraph\", \"graph_description\" },\n    { \"filter_complex_threads\", HAS_ARG | OPT_INT,                   { &filter_complex_nbthreads },\n        \"number of threads for -filter_complex\" },\n    { \"lavfi\",          HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_filter_complex },\n        \"create a complex filtergraph\", \"graph_description\" },\n    { \"filter_complex_script\", HAS_ARG | OPT_EXPERT,                 { .func_arg = opt_filter_complex_script },\n        \"read complex filtergraph description from a file\", \"filename\" },\n    { \"auto_conversion_filters\", OPT_BOOL | OPT_EXPERT,              { &auto_conversion_filters },\n        \"enable automatic conversion filters globally\" },\n    { \"stats\",          OPT_BOOL,                                    { &print_stats },\n        \"print progress report during encoding\", },\n    { \"stats_period\",    HAS_ARG | OPT_EXPERT,                       { .func_arg = opt_stats_period },\n        \"set the period at which ffmpeg updates stats and -progress output\", \"time\" },\n    { \"attach\",         HAS_ARG | OPT_PERFILE | OPT_EXPERT |\n                        OPT_OUTPUT,                                  { .func_arg = opt_attach },\n        \"add an attachment to the output file\", \"filename\" },\n    { \"dump_attachment\", HAS_ARG | OPT_STRING | OPT_SPEC |\n                         OPT_EXPERT | OPT_INPUT,                     { .off = OFFSET(dump_attachment) },\n        \"extract an attachment into a file\", \"filename\" },\n    { \"stream_loop\", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_INPUT |\n                        OPT_OFFSET,                                  { .off = OFFSET(loop) }, \"set number of times input stream shall be looped\", \"loop count\" },\n    { \"debug_ts\",       OPT_BOOL | OPT_EXPERT,                       { &debug_ts },\n        \"print timestamp debugging info\" },\n    { \"max_error_rate\",  HAS_ARG | OPT_FLOAT,                        { &max_error_rate },\n        \"ratio of decoding errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success.\", \"maximum error rate\" },\n    { \"discard\",        OPT_STRING | HAS_ARG | OPT_SPEC |\n                        OPT_INPUT,                                   { .off = OFFSET(discard) },\n        \"discard\", \"\" },\n    { \"disposition\",    OPT_STRING | HAS_ARG | OPT_SPEC |\n                        OPT_OUTPUT,                                  { .off = OFFSET(disposition) },\n        \"disposition\", \"\" },\n    { \"thread_queue_size\", HAS_ARG | OPT_INT | OPT_OFFSET | OPT_EXPERT | OPT_INPUT,\n                                                                     { .off = OFFSET(thread_queue_size) },\n        \"set the maximum number of queued packets from the demuxer\" },\n    { \"find_stream_info\", OPT_BOOL | OPT_PERFILE | OPT_INPUT | OPT_EXPERT, { &find_stream_info },\n        \"read and decode the streams to fill missing information with heuristics\" },\n    { \"bits_per_raw_sample\", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT,\n        { .off = OFFSET(bits_per_raw_sample) },\n        \"set the number of bits per raw sample\", \"number\" },\n\n    /* video options */\n    { \"vframes\",      OPT_VIDEO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_video_frames },\n        \"set the number of video frames to output\", \"number\" },\n    { \"r\",            OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC |\n                      OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(frame_rates) },\n        \"set frame rate (Hz value, fraction or abbreviation)\", \"rate\" },\n    { \"fpsmax\",       OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(max_frame_rates) },\n        \"set max frame rate (Hz value, fraction or abbreviation)\", \"rate\" },\n    { \"s\",            OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC |\n                      OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(frame_sizes) },\n        \"set frame size (WxH or abbreviation)\", \"size\" },\n    { \"aspect\",       OPT_VIDEO | HAS_ARG  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(frame_aspect_ratios) },\n        \"set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)\", \"aspect\" },\n    { \"pix_fmt\",      OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC |\n                      OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(frame_pix_fmts) },\n        \"set pixel format\", \"format\" },\n    { \"vn\",           OPT_VIDEO | OPT_BOOL  | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },\n        \"disable video\" },\n    { \"rc_override\",  OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(rc_overrides) },\n        \"rate control override for specific intervals\", \"override\" },\n    { \"vcodec\",       OPT_VIDEO | HAS_ARG  | OPT_PERFILE | OPT_INPUT |\n                      OPT_OUTPUT,                                                { .func_arg = opt_video_codec },\n        \"force video codec ('copy' to copy stream)\", \"codec\" },\n    { \"timecode\",     OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,            { .func_arg = opt_timecode },\n        \"set initial TimeCode value.\", \"hh:mm:ss[:;.]ff\" },\n    { \"pass\",         OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT,     { .off = OFFSET(pass) },\n        \"select the pass number (1 to 3)\", \"n\" },\n    { \"passlogfile\",  OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(passlogfiles) },\n        \"select two pass log file name prefix\", \"prefix\" },\n    { \"psnr\",         OPT_VIDEO | OPT_BOOL | OPT_EXPERT,                         { &do_psnr },\n        \"calculate PSNR of compressed frames\" },\n    { \"vstats\",       OPT_VIDEO | OPT_EXPERT ,                                   { .func_arg = opt_vstats },\n        \"dump video coding statistics to file\" },\n    { \"vstats_file\",  OPT_VIDEO | HAS_ARG | OPT_EXPERT ,                         { .func_arg = opt_vstats_file },\n        \"dump video coding statistics to file\", \"file\" },\n    { \"vstats_version\",  OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT ,            { &vstats_version },\n        \"Version of the vstats format to use.\"},\n    { \"vf\",           OPT_VIDEO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_video_filters },\n        \"set video filters\", \"filter_graph\" },\n    { \"intra_matrix\", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(intra_matrices) },\n        \"specify intra matrix coeffs\", \"matrix\" },\n    { \"inter_matrix\", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(inter_matrices) },\n        \"specify inter matrix coeffs\", \"matrix\" },\n    { \"chroma_intra_matrix\", OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_STRING | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(chroma_intra_matrices) },\n        \"specify intra matrix coeffs\", \"matrix\" },\n    { \"top\",          OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_INT| OPT_SPEC |\n                      OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(top_field_first) },\n        \"top=1/bottom=0/auto=-1 field first\", \"\" },\n    { \"vtag\",         OPT_VIDEO | HAS_ARG | OPT_EXPERT  | OPT_PERFILE |\n                      OPT_INPUT | OPT_OUTPUT,                                    { .func_arg = opt_old2new },\n        \"force video tag/fourcc\", \"fourcc/tag\" },\n    { \"qphist\",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },\n        \"show QP histogram\" },\n    { \"fps_mode\",     OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT |\n                      OPT_SPEC | OPT_OUTPUT,                                     { .off = OFFSET(fps_mode) },\n        \"set framerate mode for matching video streams; overrides vsync\" },\n    { \"force_fps\",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC |\n                      OPT_OUTPUT,                                                { .off = OFFSET(force_fps) },\n        \"force the selected framerate, disable the best supported framerate selection\" },\n    { \"streamid\",     OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |\n                      OPT_OUTPUT,                                                { .func_arg = opt_streamid },\n        \"set the value of an outfile streamid\", \"streamIndex:value\" },\n    { \"force_key_frames\", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |\n                          OPT_SPEC | OPT_OUTPUT,                                 { .off = OFFSET(forced_key_frames) },\n        \"force key frames at specified timestamps\", \"timestamps\" },\n    { \"ab\",           OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,            { .func_arg = opt_bitrate },\n        \"audio bitrate (please use -b:a)\", \"bitrate\" },\n    { \"b\",            OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,            { .func_arg = opt_bitrate },\n        \"video bitrate (please use -b:v)\", \"bitrate\" },\n    { \"hwaccel\",          OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |\n                          OPT_SPEC | OPT_INPUT,                                  { .off = OFFSET(hwaccels) },\n        \"use HW accelerated decoding\", \"hwaccel name\" },\n    { \"hwaccel_device\",   OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |\n                          OPT_SPEC | OPT_INPUT,                                  { .off = OFFSET(hwaccel_devices) },\n        \"select a device for HW acceleration\", \"devicename\" },\n    { \"hwaccel_output_format\", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |\n                          OPT_SPEC | OPT_INPUT,                                  { .off = OFFSET(hwaccel_output_formats) },\n        \"select output format used with HW accelerated decoding\", \"format\" },\n    { \"hwaccels\",         OPT_EXIT,                                              { .func_arg = show_hwaccels },\n        \"show available HW acceleration methods\" },\n    { \"autorotate\",       HAS_ARG | OPT_BOOL | OPT_SPEC |\n                          OPT_EXPERT | OPT_INPUT,                                { .off = OFFSET(autorotate) },\n        \"automatically insert correct rotate filters\" },\n    { \"autoscale\",        HAS_ARG | OPT_BOOL | OPT_SPEC |\n                          OPT_EXPERT | OPT_OUTPUT,                               { .off = OFFSET(autoscale) },\n        \"automatically insert a scale filter at the end of the filter graph\" },\n\n    /* audio options */\n    { \"aframes\",        OPT_AUDIO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_audio_frames },\n        \"set the number of audio frames to output\", \"number\" },\n    { \"aq\",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_audio_qscale },\n        \"set audio quality (codec-specific)\", \"quality\", },\n    { \"ar\",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC |\n                        OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(audio_sample_rate) },\n        \"set audio sampling rate (in Hz)\", \"rate\" },\n    { \"ac\",             OPT_AUDIO | HAS_ARG  | OPT_INT | OPT_SPEC |\n                        OPT_INPUT | OPT_OUTPUT,                                    { .off = OFFSET(audio_channels) },\n        \"set number of audio channels\", \"channels\" },\n    { \"an\",             OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(audio_disable) },\n        \"disable audio\" },\n    { \"acodec\",         OPT_AUDIO | HAS_ARG  | OPT_PERFILE |\n                        OPT_INPUT | OPT_OUTPUT,                                    { .func_arg = opt_audio_codec },\n        \"force audio codec ('copy' to copy stream)\", \"codec\" },\n    { \"atag\",           OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_PERFILE |\n                        OPT_OUTPUT,                                                { .func_arg = opt_old2new },\n        \"force audio tag/fourcc\", \"fourcc/tag\" },\n    { \"vol\",            OPT_AUDIO | HAS_ARG  | OPT_INT,                            { &audio_volume },\n        \"change audio volume (256=normal)\" , \"volume\" },\n    { \"sample_fmt\",     OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_SPEC |\n                        OPT_STRING | OPT_INPUT | OPT_OUTPUT,                       { .off = OFFSET(sample_fmts) },\n        \"set sample format\", \"format\" },\n    { \"channel_layout\", OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_SPEC |\n                        OPT_STRING | OPT_INPUT | OPT_OUTPUT,                       { .off = OFFSET(audio_ch_layouts) },\n        \"set channel layout\", \"layout\" },\n    { \"ch_layout\",      OPT_AUDIO | HAS_ARG  | OPT_EXPERT | OPT_SPEC |\n                        OPT_STRING | OPT_INPUT | OPT_OUTPUT,                       { .off = OFFSET(audio_ch_layouts) },\n        \"set channel layout\", \"layout\" },\n    { \"af\",             OPT_AUDIO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_audio_filters },\n        \"set audio filters\", \"filter_graph\" },\n    { \"guess_layout_max\", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(guess_layout_max) },\n      \"set the maximum number of channels to try to guess the channel layout\" },\n\n    /* subtitle options */\n    { \"sn\",     OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },\n        \"disable subtitle\" },\n    { \"scodec\", OPT_SUBTITLE | HAS_ARG  | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },\n        \"force subtitle codec ('copy' to copy stream)\", \"codec\" },\n    { \"stag\",   OPT_SUBTITLE | HAS_ARG  | OPT_EXPERT  | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new }\n        , \"force subtitle tag/fourcc\", \"fourcc/tag\" },\n    { \"fix_sub_duration\", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC | OPT_INPUT, { .off = OFFSET(fix_sub_duration) },\n        \"fix subtitles duration\" },\n    { \"canvas_size\", OPT_SUBTITLE | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFFSET(canvas_sizes) },\n        \"set canvas size (WxH or abbreviation)\", \"size\" },\n\n    /* muxer options */\n    { \"muxdelay\",   OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },\n        \"set the maximum demux-decode delay\", \"seconds\" },\n    { \"muxpreload\", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },\n        \"set the initial demux-decode delay\", \"seconds\" },\n    { \"sdp_file\", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file },\n        \"specify a file in which to print sdp information\", \"file\" },\n\n    { \"time_base\", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(time_bases) },\n        \"set the desired time base hint for output stream (1:24, 1:48000 or 0.04166, 2.0833e-5)\", \"ratio\" },\n    { \"enc_time_base\", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(enc_time_bases) },\n        \"set the desired time base for the encoder (1:24, 1:48000 or 0.04166, 2.0833e-5). \"\n        \"two special values are defined - \"\n        \"0 = use frame rate (video) or sample rate (audio),\"\n        \"-1 = match source time base\", \"ratio\" },\n\n    { \"bsf\", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },\n        \"A comma-separated list of bitstream filters\", \"bitstream_filters\" },\n    { \"absf\", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },\n        \"deprecated\", \"audio bitstream_filters\" },\n    { \"vbsf\", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },\n        \"deprecated\", \"video bitstream_filters\" },\n\n    { \"apre\", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT,    { .func_arg = opt_preset },\n        \"set the audio options to the indicated preset\", \"preset\" },\n    { \"vpre\", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT,    { .func_arg = opt_preset },\n        \"set the video options to the indicated preset\", \"preset\" },\n    { \"spre\", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },\n        \"set the subtitle options to the indicated preset\", \"preset\" },\n    { \"fpre\", HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT,                { .func_arg = opt_preset },\n        \"set options from indicated preset file\", \"filename\" },\n\n    { \"max_muxing_queue_size\", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(max_muxing_queue_size) },\n        \"maximum number of packets that can be buffered while waiting for all streams to initialize\", \"packets\" },\n    { \"muxing_queue_data_threshold\", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(muxing_queue_data_threshold) },\n        \"set the threshold after which max_muxing_queue_size is taken into account\", \"bytes\" },\n\n    /* data codec support */\n    { \"dcodec\", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },\n        \"force data codec ('copy' to copy stream)\", \"codec\" },\n    { \"dn\", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(data_disable) },\n        \"disable data\" },\n\n#if CONFIG_VAAPI\n    { \"vaapi_device\", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vaapi_device },\n        \"set VAAPI hardware device (DRM path or X11 display name)\", \"device\" },\n#endif\n\n#if CONFIG_QSV\n    { \"qsv_device\", HAS_ARG | OPT_EXPERT, { .func_arg = opt_qsv_device },\n        \"set QSV hardware device (DirectX adapter index, DRM path or X11 display name)\", \"device\"},\n#endif\n\n    { \"init_hw_device\", HAS_ARG | OPT_EXPERT, { .func_arg = opt_init_hw_device },\n        \"initialise hardware device\", \"args\" },\n    { \"filter_hw_device\", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_hw_device },\n        \"set hardware device used when filtering\", \"device\" },\n\n    { NULL, },\n};\n"
  },
  {
    "path": "src/fftools/ffplay.c",
    "content": "/*\n * Copyright (c) 2003 Fabrice Bellard\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * simple media player based on the FFmpeg libraries\n */\n\n#include \"config.h\"\n#include \"config_components.h\"\n#include <inttypes.h>\n#include <math.h>\n#include <limits.h>\n#include <signal.h>\n#include <stdint.h>\n\n#include \"libavutil/avstring.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/eval.h\"\n#include \"libavutil/mathematics.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/imgutils.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/fifo.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/samplefmt.h\"\n#include \"libavutil/time.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavformat/avformat.h\"\n#include \"libavdevice/avdevice.h\"\n#include \"libswscale/swscale.h\"\n#include \"libavutil/opt.h\"\n#include \"libavcodec/avfft.h\"\n#include \"libswresample/swresample.h\"\n\n#if CONFIG_AVFILTER\n# include \"libavfilter/avfilter.h\"\n# include \"libavfilter/buffersink.h\"\n# include \"libavfilter/buffersrc.h\"\n#endif\n\n#include <SDL.h>\n#include <SDL_thread.h>\n\n#include \"cmdutils.h\"\n#include \"opt_common.h\"\n\nconst char program_name[] = \"ffplay\";\nconst int program_birth_year = 2003;\n\n#define MAX_QUEUE_SIZE (15 * 1024 * 1024)\n#define MIN_FRAMES 25\n#define EXTERNAL_CLOCK_MIN_FRAMES 2\n#define EXTERNAL_CLOCK_MAX_FRAMES 10\n\n/* Minimum SDL audio buffer size, in samples. */\n#define SDL_AUDIO_MIN_BUFFER_SIZE 512\n/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */\n#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30\n\n/* Step size for volume control in dB */\n#define SDL_VOLUME_STEP (0.75)\n\n/* no AV sync correction is done if below the minimum AV sync threshold */\n#define AV_SYNC_THRESHOLD_MIN 0.04\n/* AV sync correction is done if above the maximum AV sync threshold */\n#define AV_SYNC_THRESHOLD_MAX 0.1\n/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */\n#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1\n/* no AV correction is done if too big error */\n#define AV_NOSYNC_THRESHOLD 10.0\n\n/* maximum audio speed change to get correct sync */\n#define SAMPLE_CORRECTION_PERCENT_MAX 10\n\n/* external clock speed adjustment constants for realtime sources based on buffer fullness */\n#define EXTERNAL_CLOCK_SPEED_MIN  0.900\n#define EXTERNAL_CLOCK_SPEED_MAX  1.010\n#define EXTERNAL_CLOCK_SPEED_STEP 0.001\n\n/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */\n#define AUDIO_DIFF_AVG_NB   20\n\n/* polls for possible required screen refresh at least this often, should be less than 1/fps */\n#define REFRESH_RATE 0.01\n\n/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */\n/* TODO: We assume that a decoded and resampled frame fits into this buffer */\n#define SAMPLE_ARRAY_SIZE (8 * 65536)\n\n#define CURSOR_HIDE_DELAY 1000000\n\n#define USE_ONEPASS_SUBTITLE_RENDER 1\n\nstatic unsigned sws_flags = SWS_BICUBIC;\n\ntypedef struct MyAVPacketList {\n    AVPacket *pkt;\n    int serial;\n} MyAVPacketList;\n\ntypedef struct PacketQueue {\n    AVFifo *pkt_list;\n    int nb_packets;\n    int size;\n    int64_t duration;\n    int abort_request;\n    int serial;\n    SDL_mutex *mutex;\n    SDL_cond *cond;\n} PacketQueue;\n\n#define VIDEO_PICTURE_QUEUE_SIZE 3\n#define SUBPICTURE_QUEUE_SIZE 16\n#define SAMPLE_QUEUE_SIZE 9\n#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))\n\ntypedef struct AudioParams {\n    int freq;\n    AVChannelLayout ch_layout;\n    enum AVSampleFormat fmt;\n    int frame_size;\n    int bytes_per_sec;\n} AudioParams;\n\ntypedef struct Clock {\n    double pts;           /* clock base */\n    double pts_drift;     /* clock base minus time at which we updated the clock */\n    double last_updated;\n    double speed;\n    int serial;           /* clock is based on a packet with this serial */\n    int paused;\n    int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */\n} Clock;\n\n/* Common struct for handling all types of decoded data and allocated render buffers. */\ntypedef struct Frame {\n    AVFrame *frame;\n    AVSubtitle sub;\n    int serial;\n    double pts;           /* presentation timestamp for the frame */\n    double duration;      /* estimated duration of the frame */\n    int64_t pos;          /* byte position of the frame in the input file */\n    int width;\n    int height;\n    int format;\n    AVRational sar;\n    int uploaded;\n    int flip_v;\n} Frame;\n\ntypedef struct FrameQueue {\n    Frame queue[FRAME_QUEUE_SIZE];\n    int rindex;\n    int windex;\n    int size;\n    int max_size;\n    int keep_last;\n    int rindex_shown;\n    SDL_mutex *mutex;\n    SDL_cond *cond;\n    PacketQueue *pktq;\n} FrameQueue;\n\nenum {\n    AV_SYNC_AUDIO_MASTER, /* default choice */\n    AV_SYNC_VIDEO_MASTER,\n    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */\n};\n\ntypedef struct Decoder {\n    AVPacket *pkt;\n    PacketQueue *queue;\n    AVCodecContext *avctx;\n    int pkt_serial;\n    int finished;\n    int packet_pending;\n    SDL_cond *empty_queue_cond;\n    int64_t start_pts;\n    AVRational start_pts_tb;\n    int64_t next_pts;\n    AVRational next_pts_tb;\n    SDL_Thread *decoder_tid;\n} Decoder;\n\ntypedef struct VideoState {\n    SDL_Thread *read_tid;\n    const AVInputFormat *iformat;\n    int abort_request;\n    int force_refresh;\n    int paused;\n    int last_paused;\n    int queue_attachments_req;\n    int seek_req;\n    int seek_flags;\n    int64_t seek_pos;\n    int64_t seek_rel;\n    int read_pause_return;\n    AVFormatContext *ic;\n    int realtime;\n\n    Clock audclk;\n    Clock vidclk;\n    Clock extclk;\n\n    FrameQueue pictq;\n    FrameQueue subpq;\n    FrameQueue sampq;\n\n    Decoder auddec;\n    Decoder viddec;\n    Decoder subdec;\n\n    int audio_stream;\n\n    int av_sync_type;\n\n    double audio_clock;\n    int audio_clock_serial;\n    double audio_diff_cum; /* used for AV difference average computation */\n    double audio_diff_avg_coef;\n    double audio_diff_threshold;\n    int audio_diff_avg_count;\n    AVStream *audio_st;\n    PacketQueue audioq;\n    int audio_hw_buf_size;\n    uint8_t *audio_buf;\n    uint8_t *audio_buf1;\n    unsigned int audio_buf_size; /* in bytes */\n    unsigned int audio_buf1_size;\n    int audio_buf_index; /* in bytes */\n    int audio_write_buf_size;\n    int audio_volume;\n    int muted;\n    struct AudioParams audio_src;\n#if CONFIG_AVFILTER\n    struct AudioParams audio_filter_src;\n#endif\n    struct AudioParams audio_tgt;\n    struct SwrContext *swr_ctx;\n    int frame_drops_early;\n    int frame_drops_late;\n\n    enum ShowMode {\n        SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB\n    } show_mode;\n    int16_t sample_array[SAMPLE_ARRAY_SIZE];\n    int sample_array_index;\n    int last_i_start;\n    RDFTContext *rdft;\n    int rdft_bits;\n    FFTSample *rdft_data;\n    int xpos;\n    double last_vis_time;\n    SDL_Texture *vis_texture;\n    SDL_Texture *sub_texture;\n    SDL_Texture *vid_texture;\n\n    int subtitle_stream;\n    AVStream *subtitle_st;\n    PacketQueue subtitleq;\n\n    double frame_timer;\n    double frame_last_returned_time;\n    double frame_last_filter_delay;\n    int video_stream;\n    AVStream *video_st;\n    PacketQueue videoq;\n    double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity\n    struct SwsContext *img_convert_ctx;\n    struct SwsContext *sub_convert_ctx;\n    int eof;\n\n    char *filename;\n    int width, height, xleft, ytop;\n    int step;\n\n#if CONFIG_AVFILTER\n    int vfilter_idx;\n    AVFilterContext *in_video_filter;   // the first filter in the video chain\n    AVFilterContext *out_video_filter;  // the last filter in the video chain\n    AVFilterContext *in_audio_filter;   // the first filter in the audio chain\n    AVFilterContext *out_audio_filter;  // the last filter in the audio chain\n    AVFilterGraph *agraph;              // audio filter graph\n#endif\n\n    int last_video_stream, last_audio_stream, last_subtitle_stream;\n\n    SDL_cond *continue_read_thread;\n} VideoState;\n\n/* options specified by the user */\nstatic const AVInputFormat *file_iformat;\nstatic const char *input_filename;\nstatic const char *window_title;\nstatic int default_width  = 640;\nstatic int default_height = 480;\nstatic int screen_width  = 0;\nstatic int screen_height = 0;\nstatic int screen_left = SDL_WINDOWPOS_CENTERED;\nstatic int screen_top = SDL_WINDOWPOS_CENTERED;\nstatic int audio_disable;\nstatic int video_disable;\nstatic int subtitle_disable;\nstatic const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};\nstatic int seek_by_bytes = -1;\nstatic float seek_interval = 10;\nstatic int display_disable;\nstatic int borderless;\nstatic int alwaysontop;\nstatic int startup_volume = 100;\nstatic int show_status = -1;\nstatic int av_sync_type = AV_SYNC_AUDIO_MASTER;\nstatic int64_t start_time = AV_NOPTS_VALUE;\nstatic int64_t duration = AV_NOPTS_VALUE;\nstatic int fast = 0;\nstatic int genpts = 0;\nstatic int lowres = 0;\nstatic int decoder_reorder_pts = -1;\nstatic int autoexit;\nstatic int exit_on_keydown;\nstatic int exit_on_mousedown;\nstatic int loop = 1;\nstatic int framedrop = -1;\nstatic int infinite_buffer = -1;\nstatic enum ShowMode show_mode = SHOW_MODE_NONE;\nstatic const char *audio_codec_name;\nstatic const char *subtitle_codec_name;\nstatic const char *video_codec_name;\ndouble rdftspeed = 0.02;\nstatic int64_t cursor_last_shown;\nstatic int cursor_hidden = 0;\n#if CONFIG_AVFILTER\nstatic const char **vfilters_list = NULL;\nstatic int nb_vfilters = 0;\nstatic char *afilters = NULL;\n#endif\nstatic int autorotate = 1;\nstatic int find_stream_info = 1;\nstatic int filter_nbthreads = 0;\n\n/* current context */\nstatic int is_full_screen;\nstatic int64_t audio_callback_time;\n\n#define FF_QUIT_EVENT    (SDL_USEREVENT + 2)\n\nstatic SDL_Window *window;\nstatic SDL_Renderer *renderer;\nstatic SDL_RendererInfo renderer_info = {0};\nstatic SDL_AudioDeviceID audio_dev;\n\nstatic const struct TextureFormatEntry {\n    enum AVPixelFormat format;\n    int texture_fmt;\n} sdl_texture_format_map[] = {\n    { AV_PIX_FMT_RGB8,           SDL_PIXELFORMAT_RGB332 },\n    { AV_PIX_FMT_RGB444,         SDL_PIXELFORMAT_RGB444 },\n    { AV_PIX_FMT_RGB555,         SDL_PIXELFORMAT_RGB555 },\n    { AV_PIX_FMT_BGR555,         SDL_PIXELFORMAT_BGR555 },\n    { AV_PIX_FMT_RGB565,         SDL_PIXELFORMAT_RGB565 },\n    { AV_PIX_FMT_BGR565,         SDL_PIXELFORMAT_BGR565 },\n    { AV_PIX_FMT_RGB24,          SDL_PIXELFORMAT_RGB24 },\n    { AV_PIX_FMT_BGR24,          SDL_PIXELFORMAT_BGR24 },\n    { AV_PIX_FMT_0RGB32,         SDL_PIXELFORMAT_RGB888 },\n    { AV_PIX_FMT_0BGR32,         SDL_PIXELFORMAT_BGR888 },\n    { AV_PIX_FMT_NE(RGB0, 0BGR), SDL_PIXELFORMAT_RGBX8888 },\n    { AV_PIX_FMT_NE(BGR0, 0RGB), SDL_PIXELFORMAT_BGRX8888 },\n    { AV_PIX_FMT_RGB32,          SDL_PIXELFORMAT_ARGB8888 },\n    { AV_PIX_FMT_RGB32_1,        SDL_PIXELFORMAT_RGBA8888 },\n    { AV_PIX_FMT_BGR32,          SDL_PIXELFORMAT_ABGR8888 },\n    { AV_PIX_FMT_BGR32_1,        SDL_PIXELFORMAT_BGRA8888 },\n    { AV_PIX_FMT_YUV420P,        SDL_PIXELFORMAT_IYUV },\n    { AV_PIX_FMT_YUYV422,        SDL_PIXELFORMAT_YUY2 },\n    { AV_PIX_FMT_UYVY422,        SDL_PIXELFORMAT_UYVY },\n    { AV_PIX_FMT_NONE,           SDL_PIXELFORMAT_UNKNOWN },\n};\n\n#if CONFIG_AVFILTER\nstatic int opt_add_vfilter(void *optctx, const char *opt, const char *arg)\n{\n    GROW_ARRAY(vfilters_list, nb_vfilters);\n    vfilters_list[nb_vfilters - 1] = arg;\n    return 0;\n}\n#endif\n\nstatic inline\nint cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,\n                   enum AVSampleFormat fmt2, int64_t channel_count2)\n{\n    /* If channel count == 1, planar and non-planar formats are the same */\n    if (channel_count1 == 1 && channel_count2 == 1)\n        return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);\n    else\n        return channel_count1 != channel_count2 || fmt1 != fmt2;\n}\n\nstatic int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)\n{\n    MyAVPacketList pkt1;\n    int ret;\n\n    if (q->abort_request)\n       return -1;\n\n\n    pkt1.pkt = pkt;\n    pkt1.serial = q->serial;\n\n    ret = av_fifo_write(q->pkt_list, &pkt1, 1);\n    if (ret < 0)\n        return ret;\n    q->nb_packets++;\n    q->size += pkt1.pkt->size + sizeof(pkt1);\n    q->duration += pkt1.pkt->duration;\n    /* XXX: should duplicate packet data in DV case */\n    SDL_CondSignal(q->cond);\n    return 0;\n}\n\nstatic int packet_queue_put(PacketQueue *q, AVPacket *pkt)\n{\n    AVPacket *pkt1;\n    int ret;\n\n    pkt1 = av_packet_alloc();\n    if (!pkt1) {\n        av_packet_unref(pkt);\n        return -1;\n    }\n    av_packet_move_ref(pkt1, pkt);\n\n    SDL_LockMutex(q->mutex);\n    ret = packet_queue_put_private(q, pkt1);\n    SDL_UnlockMutex(q->mutex);\n\n    if (ret < 0)\n        av_packet_free(&pkt1);\n\n    return ret;\n}\n\nstatic int packet_queue_put_nullpacket(PacketQueue *q, AVPacket *pkt, int stream_index)\n{\n    pkt->stream_index = stream_index;\n    return packet_queue_put(q, pkt);\n}\n\n/* packet queue handling */\nstatic int packet_queue_init(PacketQueue *q)\n{\n    memset(q, 0, sizeof(PacketQueue));\n    q->pkt_list = av_fifo_alloc2(1, sizeof(MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW);\n    if (!q->pkt_list)\n        return AVERROR(ENOMEM);\n    q->mutex = SDL_CreateMutex();\n    if (!q->mutex) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    q->cond = SDL_CreateCond();\n    if (!q->cond) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    q->abort_request = 1;\n    return 0;\n}\n\nstatic void packet_queue_flush(PacketQueue *q)\n{\n    MyAVPacketList pkt1;\n\n    SDL_LockMutex(q->mutex);\n    while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0)\n        av_packet_free(&pkt1.pkt);\n    q->nb_packets = 0;\n    q->size = 0;\n    q->duration = 0;\n    q->serial++;\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic void packet_queue_destroy(PacketQueue *q)\n{\n    packet_queue_flush(q);\n    av_fifo_freep2(&q->pkt_list);\n    SDL_DestroyMutex(q->mutex);\n    SDL_DestroyCond(q->cond);\n}\n\nstatic void packet_queue_abort(PacketQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n\n    q->abort_request = 1;\n\n    SDL_CondSignal(q->cond);\n\n    SDL_UnlockMutex(q->mutex);\n}\n\nstatic void packet_queue_start(PacketQueue *q)\n{\n    SDL_LockMutex(q->mutex);\n    q->abort_request = 0;\n    q->serial++;\n    SDL_UnlockMutex(q->mutex);\n}\n\n/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */\nstatic int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)\n{\n    MyAVPacketList pkt1;\n    int ret;\n\n    SDL_LockMutex(q->mutex);\n\n    for (;;) {\n        if (q->abort_request) {\n            ret = -1;\n            break;\n        }\n\n        if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) {\n            q->nb_packets--;\n            q->size -= pkt1.pkt->size + sizeof(pkt1);\n            q->duration -= pkt1.pkt->duration;\n            av_packet_move_ref(pkt, pkt1.pkt);\n            if (serial)\n                *serial = pkt1.serial;\n            av_packet_free(&pkt1.pkt);\n            ret = 1;\n            break;\n        } else if (!block) {\n            ret = 0;\n            break;\n        } else {\n            SDL_CondWait(q->cond, q->mutex);\n        }\n    }\n    SDL_UnlockMutex(q->mutex);\n    return ret;\n}\n\nstatic int decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {\n    memset(d, 0, sizeof(Decoder));\n    d->pkt = av_packet_alloc();\n    if (!d->pkt)\n        return AVERROR(ENOMEM);\n    d->avctx = avctx;\n    d->queue = queue;\n    d->empty_queue_cond = empty_queue_cond;\n    d->start_pts = AV_NOPTS_VALUE;\n    d->pkt_serial = -1;\n    return 0;\n}\n\nstatic int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {\n    int ret = AVERROR(EAGAIN);\n\n    for (;;) {\n        if (d->queue->serial == d->pkt_serial) {\n            do {\n                if (d->queue->abort_request)\n                    return -1;\n\n                switch (d->avctx->codec_type) {\n                    case AVMEDIA_TYPE_VIDEO:\n                        ret = avcodec_receive_frame(d->avctx, frame);\n                        if (ret >= 0) {\n                            if (decoder_reorder_pts == -1) {\n                                frame->pts = frame->best_effort_timestamp;\n                            } else if (!decoder_reorder_pts) {\n                                frame->pts = frame->pkt_dts;\n                            }\n                        }\n                        break;\n                    case AVMEDIA_TYPE_AUDIO:\n                        ret = avcodec_receive_frame(d->avctx, frame);\n                        if (ret >= 0) {\n                            AVRational tb = (AVRational){1, frame->sample_rate};\n                            if (frame->pts != AV_NOPTS_VALUE)\n                                frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb);\n                            else if (d->next_pts != AV_NOPTS_VALUE)\n                                frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);\n                            if (frame->pts != AV_NOPTS_VALUE) {\n                                d->next_pts = frame->pts + frame->nb_samples;\n                                d->next_pts_tb = tb;\n                            }\n                        }\n                        break;\n                }\n                if (ret == AVERROR_EOF) {\n                    d->finished = d->pkt_serial;\n                    avcodec_flush_buffers(d->avctx);\n                    return 0;\n                }\n                if (ret >= 0)\n                    return 1;\n            } while (ret != AVERROR(EAGAIN));\n        }\n\n        do {\n            if (d->queue->nb_packets == 0)\n                SDL_CondSignal(d->empty_queue_cond);\n            if (d->packet_pending) {\n                d->packet_pending = 0;\n            } else {\n                int old_serial = d->pkt_serial;\n                if (packet_queue_get(d->queue, d->pkt, 1, &d->pkt_serial) < 0)\n                    return -1;\n                if (old_serial != d->pkt_serial) {\n                    avcodec_flush_buffers(d->avctx);\n                    d->finished = 0;\n                    d->next_pts = d->start_pts;\n                    d->next_pts_tb = d->start_pts_tb;\n                }\n            }\n            if (d->queue->serial == d->pkt_serial)\n                break;\n            av_packet_unref(d->pkt);\n        } while (1);\n\n        if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {\n            int got_frame = 0;\n            ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, d->pkt);\n            if (ret < 0) {\n                ret = AVERROR(EAGAIN);\n            } else {\n                if (got_frame && !d->pkt->data) {\n                    d->packet_pending = 1;\n                }\n                ret = got_frame ? 0 : (d->pkt->data ? AVERROR(EAGAIN) : AVERROR_EOF);\n            }\n            av_packet_unref(d->pkt);\n        } else {\n            if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) {\n                av_log(d->avctx, AV_LOG_ERROR, \"Receive_frame and send_packet both returned EAGAIN, which is an API violation.\\n\");\n                d->packet_pending = 1;\n            } else {\n                av_packet_unref(d->pkt);\n            }\n        }\n    }\n}\n\nstatic void decoder_destroy(Decoder *d) {\n    av_packet_free(&d->pkt);\n    avcodec_free_context(&d->avctx);\n}\n\nstatic void frame_queue_unref_item(Frame *vp)\n{\n    av_frame_unref(vp->frame);\n    avsubtitle_free(&vp->sub);\n}\n\nstatic int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)\n{\n    int i;\n    memset(f, 0, sizeof(FrameQueue));\n    if (!(f->mutex = SDL_CreateMutex())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    if (!(f->cond = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    f->pktq = pktq;\n    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);\n    f->keep_last = !!keep_last;\n    for (i = 0; i < f->max_size; i++)\n        if (!(f->queue[i].frame = av_frame_alloc()))\n            return AVERROR(ENOMEM);\n    return 0;\n}\n\nstatic void frame_queue_destory(FrameQueue *f)\n{\n    int i;\n    for (i = 0; i < f->max_size; i++) {\n        Frame *vp = &f->queue[i];\n        frame_queue_unref_item(vp);\n        av_frame_free(&vp->frame);\n    }\n    SDL_DestroyMutex(f->mutex);\n    SDL_DestroyCond(f->cond);\n}\n\nstatic void frame_queue_signal(FrameQueue *f)\n{\n    SDL_LockMutex(f->mutex);\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\nstatic Frame *frame_queue_peek(FrameQueue *f)\n{\n    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];\n}\n\nstatic Frame *frame_queue_peek_next(FrameQueue *f)\n{\n    return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];\n}\n\nstatic Frame *frame_queue_peek_last(FrameQueue *f)\n{\n    return &f->queue[f->rindex];\n}\n\nstatic Frame *frame_queue_peek_writable(FrameQueue *f)\n{\n    /* wait until we have space to put a new frame */\n    SDL_LockMutex(f->mutex);\n    while (f->size >= f->max_size &&\n           !f->pktq->abort_request) {\n        SDL_CondWait(f->cond, f->mutex);\n    }\n    SDL_UnlockMutex(f->mutex);\n\n    if (f->pktq->abort_request)\n        return NULL;\n\n    return &f->queue[f->windex];\n}\n\nstatic Frame *frame_queue_peek_readable(FrameQueue *f)\n{\n    /* wait until we have a readable a new frame */\n    SDL_LockMutex(f->mutex);\n    while (f->size - f->rindex_shown <= 0 &&\n           !f->pktq->abort_request) {\n        SDL_CondWait(f->cond, f->mutex);\n    }\n    SDL_UnlockMutex(f->mutex);\n\n    if (f->pktq->abort_request)\n        return NULL;\n\n    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];\n}\n\nstatic void frame_queue_push(FrameQueue *f)\n{\n    if (++f->windex == f->max_size)\n        f->windex = 0;\n    SDL_LockMutex(f->mutex);\n    f->size++;\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\nstatic void frame_queue_next(FrameQueue *f)\n{\n    if (f->keep_last && !f->rindex_shown) {\n        f->rindex_shown = 1;\n        return;\n    }\n    frame_queue_unref_item(&f->queue[f->rindex]);\n    if (++f->rindex == f->max_size)\n        f->rindex = 0;\n    SDL_LockMutex(f->mutex);\n    f->size--;\n    SDL_CondSignal(f->cond);\n    SDL_UnlockMutex(f->mutex);\n}\n\n/* return the number of undisplayed frames in the queue */\nstatic int frame_queue_nb_remaining(FrameQueue *f)\n{\n    return f->size - f->rindex_shown;\n}\n\n/* return last shown position */\nstatic int64_t frame_queue_last_pos(FrameQueue *f)\n{\n    Frame *fp = &f->queue[f->rindex];\n    if (f->rindex_shown && fp->serial == f->pktq->serial)\n        return fp->pos;\n    else\n        return -1;\n}\n\nstatic void decoder_abort(Decoder *d, FrameQueue *fq)\n{\n    packet_queue_abort(d->queue);\n    frame_queue_signal(fq);\n    SDL_WaitThread(d->decoder_tid, NULL);\n    d->decoder_tid = NULL;\n    packet_queue_flush(d->queue);\n}\n\nstatic inline void fill_rectangle(int x, int y, int w, int h)\n{\n    SDL_Rect rect;\n    rect.x = x;\n    rect.y = y;\n    rect.w = w;\n    rect.h = h;\n    if (w && h)\n        SDL_RenderFillRect(renderer, &rect);\n}\n\nstatic int realloc_texture(SDL_Texture **texture, Uint32 new_format, int new_width, int new_height, SDL_BlendMode blendmode, int init_texture)\n{\n    Uint32 format;\n    int access, w, h;\n    if (!*texture || SDL_QueryTexture(*texture, &format, &access, &w, &h) < 0 || new_width != w || new_height != h || new_format != format) {\n        void *pixels;\n        int pitch;\n        if (*texture)\n            SDL_DestroyTexture(*texture);\n        if (!(*texture = SDL_CreateTexture(renderer, new_format, SDL_TEXTUREACCESS_STREAMING, new_width, new_height)))\n            return -1;\n        if (SDL_SetTextureBlendMode(*texture, blendmode) < 0)\n            return -1;\n        if (init_texture) {\n            if (SDL_LockTexture(*texture, NULL, &pixels, &pitch) < 0)\n                return -1;\n            memset(pixels, 0, pitch * new_height);\n            SDL_UnlockTexture(*texture);\n        }\n        av_log(NULL, AV_LOG_VERBOSE, \"Created %dx%d texture with %s.\\n\", new_width, new_height, SDL_GetPixelFormatName(new_format));\n    }\n    return 0;\n}\n\nstatic void calculate_display_rect(SDL_Rect *rect,\n                                   int scr_xleft, int scr_ytop, int scr_width, int scr_height,\n                                   int pic_width, int pic_height, AVRational pic_sar)\n{\n    AVRational aspect_ratio = pic_sar;\n    int64_t width, height, x, y;\n\n    if (av_cmp_q(aspect_ratio, av_make_q(0, 1)) <= 0)\n        aspect_ratio = av_make_q(1, 1);\n\n    aspect_ratio = av_mul_q(aspect_ratio, av_make_q(pic_width, pic_height));\n\n    /* XXX: we suppose the screen has a 1.0 pixel ratio */\n    height = scr_height;\n    width = av_rescale(height, aspect_ratio.num, aspect_ratio.den) & ~1;\n    if (width > scr_width) {\n        width = scr_width;\n        height = av_rescale(width, aspect_ratio.den, aspect_ratio.num) & ~1;\n    }\n    x = (scr_width - width) / 2;\n    y = (scr_height - height) / 2;\n    rect->x = scr_xleft + x;\n    rect->y = scr_ytop  + y;\n    rect->w = FFMAX((int)width,  1);\n    rect->h = FFMAX((int)height, 1);\n}\n\nstatic void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_BlendMode *sdl_blendmode)\n{\n    int i;\n    *sdl_blendmode = SDL_BLENDMODE_NONE;\n    *sdl_pix_fmt = SDL_PIXELFORMAT_UNKNOWN;\n    if (format == AV_PIX_FMT_RGB32   ||\n        format == AV_PIX_FMT_RGB32_1 ||\n        format == AV_PIX_FMT_BGR32   ||\n        format == AV_PIX_FMT_BGR32_1)\n        *sdl_blendmode = SDL_BLENDMODE_BLEND;\n    for (i = 0; i < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; i++) {\n        if (format == sdl_texture_format_map[i].format) {\n            *sdl_pix_fmt = sdl_texture_format_map[i].texture_fmt;\n            return;\n        }\n    }\n}\n\nstatic int upload_texture(SDL_Texture **tex, AVFrame *frame, struct SwsContext **img_convert_ctx) {\n    int ret = 0;\n    Uint32 sdl_pix_fmt;\n    SDL_BlendMode sdl_blendmode;\n    get_sdl_pix_fmt_and_blendmode(frame->format, &sdl_pix_fmt, &sdl_blendmode);\n    if (realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt, frame->width, frame->height, sdl_blendmode, 0) < 0)\n        return -1;\n    switch (sdl_pix_fmt) {\n        case SDL_PIXELFORMAT_UNKNOWN:\n            /* This should only happen if we are not using avfilter... */\n            *img_convert_ctx = sws_getCachedContext(*img_convert_ctx,\n                frame->width, frame->height, frame->format, frame->width, frame->height,\n                AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL);\n            if (*img_convert_ctx != NULL) {\n                uint8_t *pixels[4];\n                int pitch[4];\n                if (!SDL_LockTexture(*tex, NULL, (void **)pixels, pitch)) {\n                    sws_scale(*img_convert_ctx, (const uint8_t * const *)frame->data, frame->linesize,\n                              0, frame->height, pixels, pitch);\n                    SDL_UnlockTexture(*tex);\n                }\n            } else {\n                av_log(NULL, AV_LOG_FATAL, \"Cannot initialize the conversion context\\n\");\n                ret = -1;\n            }\n            break;\n        case SDL_PIXELFORMAT_IYUV:\n            if (frame->linesize[0] > 0 && frame->linesize[1] > 0 && frame->linesize[2] > 0) {\n                ret = SDL_UpdateYUVTexture(*tex, NULL, frame->data[0], frame->linesize[0],\n                                                       frame->data[1], frame->linesize[1],\n                                                       frame->data[2], frame->linesize[2]);\n            } else if (frame->linesize[0] < 0 && frame->linesize[1] < 0 && frame->linesize[2] < 0) {\n                ret = SDL_UpdateYUVTexture(*tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height                    - 1), -frame->linesize[0],\n                                                       frame->data[1] + frame->linesize[1] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[1],\n                                                       frame->data[2] + frame->linesize[2] * (AV_CEIL_RSHIFT(frame->height, 1) - 1), -frame->linesize[2]);\n            } else {\n                av_log(NULL, AV_LOG_ERROR, \"Mixed negative and positive linesizes are not supported.\\n\");\n                return -1;\n            }\n            break;\n        default:\n            if (frame->linesize[0] < 0) {\n                ret = SDL_UpdateTexture(*tex, NULL, frame->data[0] + frame->linesize[0] * (frame->height - 1), -frame->linesize[0]);\n            } else {\n                ret = SDL_UpdateTexture(*tex, NULL, frame->data[0], frame->linesize[0]);\n            }\n            break;\n    }\n    return ret;\n}\n\nstatic void set_sdl_yuv_conversion_mode(AVFrame *frame)\n{\n#if SDL_VERSION_ATLEAST(2,0,8)\n    SDL_YUV_CONVERSION_MODE mode = SDL_YUV_CONVERSION_AUTOMATIC;\n    if (frame && (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUYV422 || frame->format == AV_PIX_FMT_UYVY422)) {\n        if (frame->color_range == AVCOL_RANGE_JPEG)\n            mode = SDL_YUV_CONVERSION_JPEG;\n        else if (frame->colorspace == AVCOL_SPC_BT709)\n            mode = SDL_YUV_CONVERSION_BT709;\n        else if (frame->colorspace == AVCOL_SPC_BT470BG || frame->colorspace == AVCOL_SPC_SMPTE170M)\n            mode = SDL_YUV_CONVERSION_BT601;\n    }\n    SDL_SetYUVConversionMode(mode); /* FIXME: no support for linear transfer */\n#endif\n}\n\nstatic void video_image_display(VideoState *is)\n{\n    Frame *vp;\n    Frame *sp = NULL;\n    SDL_Rect rect;\n\n    vp = frame_queue_peek_last(&is->pictq);\n    if (is->subtitle_st) {\n        if (frame_queue_nb_remaining(&is->subpq) > 0) {\n            sp = frame_queue_peek(&is->subpq);\n\n            if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {\n                if (!sp->uploaded) {\n                    uint8_t* pixels[4];\n                    int pitch[4];\n                    int i;\n                    if (!sp->width || !sp->height) {\n                        sp->width = vp->width;\n                        sp->height = vp->height;\n                    }\n                    if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0)\n                        return;\n\n                    for (i = 0; i < sp->sub.num_rects; i++) {\n                        AVSubtitleRect *sub_rect = sp->sub.rects[i];\n\n                        sub_rect->x = av_clip(sub_rect->x, 0, sp->width );\n                        sub_rect->y = av_clip(sub_rect->y, 0, sp->height);\n                        sub_rect->w = av_clip(sub_rect->w, 0, sp->width  - sub_rect->x);\n                        sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y);\n\n                        is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,\n                            sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8,\n                            sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA,\n                            0, NULL, NULL, NULL);\n                        if (!is->sub_convert_ctx) {\n                            av_log(NULL, AV_LOG_FATAL, \"Cannot initialize the conversion context\\n\");\n                            return;\n                        }\n                        if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)pixels, pitch)) {\n                            sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize,\n                                      0, sub_rect->h, pixels, pitch);\n                            SDL_UnlockTexture(is->sub_texture);\n                        }\n                    }\n                    sp->uploaded = 1;\n                }\n            } else\n                sp = NULL;\n        }\n    }\n\n    calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);\n    set_sdl_yuv_conversion_mode(vp->frame);\n\n    if (!vp->uploaded) {\n        if (upload_texture(&is->vid_texture, vp->frame, &is->img_convert_ctx) < 0) {\n            set_sdl_yuv_conversion_mode(NULL);\n            return;\n        }\n        vp->uploaded = 1;\n        vp->flip_v = vp->frame->linesize[0] < 0;\n    }\n\n    SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);\n    set_sdl_yuv_conversion_mode(NULL);\n    if (sp) {\n#if USE_ONEPASS_SUBTITLE_RENDER\n        SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect);\n#else\n        int i;\n        double xratio = (double)rect.w / (double)sp->width;\n        double yratio = (double)rect.h / (double)sp->height;\n        for (i = 0; i < sp->sub.num_rects; i++) {\n            SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i];\n            SDL_Rect target = {.x = rect.x + sub_rect->x * xratio,\n                               .y = rect.y + sub_rect->y * yratio,\n                               .w = sub_rect->w * xratio,\n                               .h = sub_rect->h * yratio};\n            SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target);\n        }\n#endif\n    }\n}\n\nstatic inline int compute_mod(int a, int b)\n{\n    return a < 0 ? a%b + b : a%b;\n}\n\nstatic void video_audio_display(VideoState *s)\n{\n    int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;\n    int ch, channels, h, h2;\n    int64_t time_diff;\n    int rdft_bits, nb_freq;\n\n    for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)\n        ;\n    nb_freq = 1 << (rdft_bits - 1);\n\n    /* compute display index : center on currently output samples */\n    channels = s->audio_tgt.ch_layout.nb_channels;\n    nb_display_channels = channels;\n    if (!s->paused) {\n        int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);\n        n = 2 * channels;\n        delay = s->audio_write_buf_size;\n        delay /= n;\n\n        /* to be more precise, we take into account the time spent since\n           the last buffer computation */\n        if (audio_callback_time) {\n            time_diff = av_gettime_relative() - audio_callback_time;\n            delay -= (time_diff * s->audio_tgt.freq) / 1000000;\n        }\n\n        delay += 2 * data_used;\n        if (delay < data_used)\n            delay = data_used;\n\n        i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);\n        if (s->show_mode == SHOW_MODE_WAVES) {\n            h = INT_MIN;\n            for (i = 0; i < 1000; i += channels) {\n                int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;\n                int a = s->sample_array[idx];\n                int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];\n                int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];\n                int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];\n                int score = a - d;\n                if (h < score && (b ^ c) < 0) {\n                    h = score;\n                    i_start = idx;\n                }\n            }\n        }\n\n        s->last_i_start = i_start;\n    } else {\n        i_start = s->last_i_start;\n    }\n\n    if (s->show_mode == SHOW_MODE_WAVES) {\n        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);\n\n        /* total height for one channel */\n        h = s->height / nb_display_channels;\n        /* graph height / 2 */\n        h2 = (h * 9) / 20;\n        for (ch = 0; ch < nb_display_channels; ch++) {\n            i = i_start + ch;\n            y1 = s->ytop + ch * h + (h / 2); /* position of center line */\n            for (x = 0; x < s->width; x++) {\n                y = (s->sample_array[i] * h2) >> 15;\n                if (y < 0) {\n                    y = -y;\n                    ys = y1 - y;\n                } else {\n                    ys = y1;\n                }\n                fill_rectangle(s->xleft + x, ys, 1, y);\n                i += channels;\n                if (i >= SAMPLE_ARRAY_SIZE)\n                    i -= SAMPLE_ARRAY_SIZE;\n            }\n        }\n\n        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);\n\n        for (ch = 1; ch < nb_display_channels; ch++) {\n            y = s->ytop + ch * h;\n            fill_rectangle(s->xleft, y, s->width, 1);\n        }\n    } else {\n        if (realloc_texture(&s->vis_texture, SDL_PIXELFORMAT_ARGB8888, s->width, s->height, SDL_BLENDMODE_NONE, 1) < 0)\n            return;\n\n        if (s->xpos >= s->width)\n            s->xpos = 0;\n        nb_display_channels= FFMIN(nb_display_channels, 2);\n        if (rdft_bits != s->rdft_bits) {\n            av_rdft_end(s->rdft);\n            av_free(s->rdft_data);\n            s->rdft = av_rdft_init(rdft_bits, DFT_R2C);\n            s->rdft_bits = rdft_bits;\n            s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data));\n        }\n        if (!s->rdft || !s->rdft_data){\n            av_log(NULL, AV_LOG_ERROR, \"Failed to allocate buffers for RDFT, switching to waves display\\n\");\n            s->show_mode = SHOW_MODE_WAVES;\n        } else {\n            FFTSample *data[2];\n            SDL_Rect rect = {.x = s->xpos, .y = 0, .w = 1, .h = s->height};\n            uint32_t *pixels;\n            int pitch;\n            for (ch = 0; ch < nb_display_channels; ch++) {\n                data[ch] = s->rdft_data + 2 * nb_freq * ch;\n                i = i_start + ch;\n                for (x = 0; x < 2 * nb_freq; x++) {\n                    double w = (x-nb_freq) * (1.0 / nb_freq);\n                    data[ch][x] = s->sample_array[i] * (1.0 - w * w);\n                    i += channels;\n                    if (i >= SAMPLE_ARRAY_SIZE)\n                        i -= SAMPLE_ARRAY_SIZE;\n                }\n                av_rdft_calc(s->rdft, data[ch]);\n            }\n            /* Least efficient way to do this, we should of course\n             * directly access it but it is more than fast enough. */\n            if (!SDL_LockTexture(s->vis_texture, &rect, (void **)&pixels, &pitch)) {\n                pitch >>= 2;\n                pixels += pitch * s->height;\n                for (y = 0; y < s->height; y++) {\n                    double w = 1 / sqrt(nb_freq);\n                    int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));\n                    int b = (nb_display_channels == 2 ) ? sqrt(w * hypot(data[1][2 * y + 0], data[1][2 * y + 1]))\n                                                        : a;\n                    a = FFMIN(a, 255);\n                    b = FFMIN(b, 255);\n                    pixels -= pitch;\n                    *pixels = (a << 16) + (b << 8) + ((a+b) >> 1);\n                }\n                SDL_UnlockTexture(s->vis_texture);\n            }\n            SDL_RenderCopy(renderer, s->vis_texture, NULL, NULL);\n        }\n        if (!s->paused)\n            s->xpos++;\n    }\n}\n\nstatic void stream_component_close(VideoState *is, int stream_index)\n{\n    AVFormatContext *ic = is->ic;\n    AVCodecParameters *codecpar;\n\n    if (stream_index < 0 || stream_index >= ic->nb_streams)\n        return;\n    codecpar = ic->streams[stream_index]->codecpar;\n\n    switch (codecpar->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        decoder_abort(&is->auddec, &is->sampq);\n        SDL_CloseAudioDevice(audio_dev);\n        decoder_destroy(&is->auddec);\n        swr_free(&is->swr_ctx);\n        av_freep(&is->audio_buf1);\n        is->audio_buf1_size = 0;\n        is->audio_buf = NULL;\n\n        if (is->rdft) {\n            av_rdft_end(is->rdft);\n            av_freep(&is->rdft_data);\n            is->rdft = NULL;\n            is->rdft_bits = 0;\n        }\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        decoder_abort(&is->viddec, &is->pictq);\n        decoder_destroy(&is->viddec);\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        decoder_abort(&is->subdec, &is->subpq);\n        decoder_destroy(&is->subdec);\n        break;\n    default:\n        break;\n    }\n\n    ic->streams[stream_index]->discard = AVDISCARD_ALL;\n    switch (codecpar->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n        is->audio_st = NULL;\n        is->audio_stream = -1;\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        is->video_st = NULL;\n        is->video_stream = -1;\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        is->subtitle_st = NULL;\n        is->subtitle_stream = -1;\n        break;\n    default:\n        break;\n    }\n}\n\nstatic void stream_close(VideoState *is)\n{\n    /* XXX: use a special url_shutdown call to abort parse cleanly */\n    is->abort_request = 1;\n    SDL_WaitThread(is->read_tid, NULL);\n\n    /* close each stream */\n    if (is->audio_stream >= 0)\n        stream_component_close(is, is->audio_stream);\n    if (is->video_stream >= 0)\n        stream_component_close(is, is->video_stream);\n    if (is->subtitle_stream >= 0)\n        stream_component_close(is, is->subtitle_stream);\n\n    avformat_close_input(&is->ic);\n\n    packet_queue_destroy(&is->videoq);\n    packet_queue_destroy(&is->audioq);\n    packet_queue_destroy(&is->subtitleq);\n\n    /* free all pictures */\n    frame_queue_destory(&is->pictq);\n    frame_queue_destory(&is->sampq);\n    frame_queue_destory(&is->subpq);\n    SDL_DestroyCond(is->continue_read_thread);\n    sws_freeContext(is->img_convert_ctx);\n    sws_freeContext(is->sub_convert_ctx);\n    av_free(is->filename);\n    if (is->vis_texture)\n        SDL_DestroyTexture(is->vis_texture);\n    if (is->vid_texture)\n        SDL_DestroyTexture(is->vid_texture);\n    if (is->sub_texture)\n        SDL_DestroyTexture(is->sub_texture);\n    av_free(is);\n}\n\nstatic void do_exit(VideoState *is)\n{\n    if (is) {\n        stream_close(is);\n    }\n    if (renderer)\n        SDL_DestroyRenderer(renderer);\n    if (window)\n        SDL_DestroyWindow(window);\n    uninit_opts();\n#if CONFIG_AVFILTER\n    av_freep(&vfilters_list);\n#endif\n    avformat_network_deinit();\n    if (show_status)\n        printf(\"\\n\");\n    SDL_Quit();\n    av_log(NULL, AV_LOG_QUIET, \"%s\", \"\");\n    exit(0);\n}\n\nstatic void sigterm_handler(int sig)\n{\n    exit(123);\n}\n\nstatic void set_default_window_size(int width, int height, AVRational sar)\n{\n    SDL_Rect rect;\n    int max_width  = screen_width  ? screen_width  : INT_MAX;\n    int max_height = screen_height ? screen_height : INT_MAX;\n    if (max_width == INT_MAX && max_height == INT_MAX)\n        max_height = height;\n    calculate_display_rect(&rect, 0, 0, max_width, max_height, width, height, sar);\n    default_width  = rect.w;\n    default_height = rect.h;\n}\n\nstatic int video_open(VideoState *is)\n{\n    int w,h;\n\n    w = screen_width ? screen_width : default_width;\n    h = screen_height ? screen_height : default_height;\n\n    if (!window_title)\n        window_title = input_filename;\n    SDL_SetWindowTitle(window, window_title);\n\n    SDL_SetWindowSize(window, w, h);\n    SDL_SetWindowPosition(window, screen_left, screen_top);\n    if (is_full_screen)\n        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);\n    SDL_ShowWindow(window);\n\n    is->width  = w;\n    is->height = h;\n\n    return 0;\n}\n\n/* display the current picture, if any */\nstatic void video_display(VideoState *is)\n{\n    if (!is->width)\n        video_open(is);\n\n    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);\n    SDL_RenderClear(renderer);\n    if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)\n        video_audio_display(is);\n    else if (is->video_st)\n        video_image_display(is);\n    SDL_RenderPresent(renderer);\n}\n\nstatic double get_clock(Clock *c)\n{\n    if (*c->queue_serial != c->serial)\n        return NAN;\n    if (c->paused) {\n        return c->pts;\n    } else {\n        double time = av_gettime_relative() / 1000000.0;\n        return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);\n    }\n}\n\nstatic void set_clock_at(Clock *c, double pts, int serial, double time)\n{\n    c->pts = pts;\n    c->last_updated = time;\n    c->pts_drift = c->pts - time;\n    c->serial = serial;\n}\n\nstatic void set_clock(Clock *c, double pts, int serial)\n{\n    double time = av_gettime_relative() / 1000000.0;\n    set_clock_at(c, pts, serial, time);\n}\n\nstatic void set_clock_speed(Clock *c, double speed)\n{\n    set_clock(c, get_clock(c), c->serial);\n    c->speed = speed;\n}\n\nstatic void init_clock(Clock *c, int *queue_serial)\n{\n    c->speed = 1.0;\n    c->paused = 0;\n    c->queue_serial = queue_serial;\n    set_clock(c, NAN, -1);\n}\n\nstatic void sync_clock_to_slave(Clock *c, Clock *slave)\n{\n    double clock = get_clock(c);\n    double slave_clock = get_clock(slave);\n    if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))\n        set_clock(c, slave_clock, slave->serial);\n}\n\nstatic int get_master_sync_type(VideoState *is) {\n    if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {\n        if (is->video_st)\n            return AV_SYNC_VIDEO_MASTER;\n        else\n            return AV_SYNC_AUDIO_MASTER;\n    } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {\n        if (is->audio_st)\n            return AV_SYNC_AUDIO_MASTER;\n        else\n            return AV_SYNC_EXTERNAL_CLOCK;\n    } else {\n        return AV_SYNC_EXTERNAL_CLOCK;\n    }\n}\n\n/* get the current master clock value */\nstatic double get_master_clock(VideoState *is)\n{\n    double val;\n\n    switch (get_master_sync_type(is)) {\n        case AV_SYNC_VIDEO_MASTER:\n            val = get_clock(&is->vidclk);\n            break;\n        case AV_SYNC_AUDIO_MASTER:\n            val = get_clock(&is->audclk);\n            break;\n        default:\n            val = get_clock(&is->extclk);\n            break;\n    }\n    return val;\n}\n\nstatic void check_external_clock_speed(VideoState *is) {\n   if (is->video_stream >= 0 && is->videoq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES ||\n       is->audio_stream >= 0 && is->audioq.nb_packets <= EXTERNAL_CLOCK_MIN_FRAMES) {\n       set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));\n   } else if ((is->video_stream < 0 || is->videoq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES) &&\n              (is->audio_stream < 0 || is->audioq.nb_packets > EXTERNAL_CLOCK_MAX_FRAMES)) {\n       set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));\n   } else {\n       double speed = is->extclk.speed;\n       if (speed != 1.0)\n           set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));\n   }\n}\n\n/* seek in the stream */\nstatic void stream_seek(VideoState *is, int64_t pos, int64_t rel, int by_bytes)\n{\n    if (!is->seek_req) {\n        is->seek_pos = pos;\n        is->seek_rel = rel;\n        is->seek_flags &= ~AVSEEK_FLAG_BYTE;\n        if (by_bytes)\n            is->seek_flags |= AVSEEK_FLAG_BYTE;\n        is->seek_req = 1;\n        SDL_CondSignal(is->continue_read_thread);\n    }\n}\n\n/* pause or resume the video */\nstatic void stream_toggle_pause(VideoState *is)\n{\n    if (is->paused) {\n        is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;\n        if (is->read_pause_return != AVERROR(ENOSYS)) {\n            is->vidclk.paused = 0;\n        }\n        set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);\n    }\n    set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);\n    is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;\n}\n\nstatic void toggle_pause(VideoState *is)\n{\n    stream_toggle_pause(is);\n    is->step = 0;\n}\n\nstatic void toggle_mute(VideoState *is)\n{\n    is->muted = !is->muted;\n}\n\nstatic void update_volume(VideoState *is, int sign, double step)\n{\n    double volume_level = is->audio_volume ? (20 * log(is->audio_volume / (double)SDL_MIX_MAXVOLUME) / log(10)) : -1000.0;\n    int new_volume = lrint(SDL_MIX_MAXVOLUME * pow(10.0, (volume_level + sign * step) / 20.0));\n    is->audio_volume = av_clip(is->audio_volume == new_volume ? (is->audio_volume + sign) : new_volume, 0, SDL_MIX_MAXVOLUME);\n}\n\nstatic void step_to_next_frame(VideoState *is)\n{\n    /* if the stream is paused unpause it, then step */\n    if (is->paused)\n        stream_toggle_pause(is);\n    is->step = 1;\n}\n\nstatic double compute_target_delay(double delay, VideoState *is)\n{\n    double sync_threshold, diff = 0;\n\n    /* update delay to follow master synchronisation source */\n    if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {\n        /* if video is slave, we try to correct big delays by\n           duplicating or deleting a frame */\n        diff = get_clock(&is->vidclk) - get_master_clock(is);\n\n        /* skip or repeat frame. We take into account the\n           delay to compute the threshold. I still don't know\n           if it is the best guess */\n        sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));\n        if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {\n            if (diff <= -sync_threshold)\n                delay = FFMAX(0, delay + diff);\n            else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)\n                delay = delay + diff;\n            else if (diff >= sync_threshold)\n                delay = 2 * delay;\n        }\n    }\n\n    av_log(NULL, AV_LOG_TRACE, \"video: delay=%0.3f A-V=%f\\n\",\n            delay, -diff);\n\n    return delay;\n}\n\nstatic double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {\n    if (vp->serial == nextvp->serial) {\n        double duration = nextvp->pts - vp->pts;\n        if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)\n            return vp->duration;\n        else\n            return duration;\n    } else {\n        return 0.0;\n    }\n}\n\nstatic void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {\n    /* update current video pts */\n    set_clock(&is->vidclk, pts, serial);\n    sync_clock_to_slave(&is->extclk, &is->vidclk);\n}\n\n/* called to display each frame */\nstatic void video_refresh(void *opaque, double *remaining_time)\n{\n    VideoState *is = opaque;\n    double time;\n\n    Frame *sp, *sp2;\n\n    if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)\n        check_external_clock_speed(is);\n\n    if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {\n        time = av_gettime_relative() / 1000000.0;\n        if (is->force_refresh || is->last_vis_time + rdftspeed < time) {\n            video_display(is);\n            is->last_vis_time = time;\n        }\n        *remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);\n    }\n\n    if (is->video_st) {\nretry:\n        if (frame_queue_nb_remaining(&is->pictq) == 0) {\n            // nothing to do, no picture to display in the queue\n        } else {\n            double last_duration, duration, delay;\n            Frame *vp, *lastvp;\n\n            /* dequeue the picture */\n            lastvp = frame_queue_peek_last(&is->pictq);\n            vp = frame_queue_peek(&is->pictq);\n\n            if (vp->serial != is->videoq.serial) {\n                frame_queue_next(&is->pictq);\n                goto retry;\n            }\n\n            if (lastvp->serial != vp->serial)\n                is->frame_timer = av_gettime_relative() / 1000000.0;\n\n            if (is->paused)\n                goto display;\n\n            /* compute nominal last_duration */\n            last_duration = vp_duration(is, lastvp, vp);\n            delay = compute_target_delay(last_duration, is);\n\n            time= av_gettime_relative()/1000000.0;\n            if (time < is->frame_timer + delay) {\n                *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);\n                goto display;\n            }\n\n            is->frame_timer += delay;\n            if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)\n                is->frame_timer = time;\n\n            SDL_LockMutex(is->pictq.mutex);\n            if (!isnan(vp->pts))\n                update_video_pts(is, vp->pts, vp->pos, vp->serial);\n            SDL_UnlockMutex(is->pictq.mutex);\n\n            if (frame_queue_nb_remaining(&is->pictq) > 1) {\n                Frame *nextvp = frame_queue_peek_next(&is->pictq);\n                duration = vp_duration(is, vp, nextvp);\n                if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){\n                    is->frame_drops_late++;\n                    frame_queue_next(&is->pictq);\n                    goto retry;\n                }\n            }\n\n            if (is->subtitle_st) {\n                while (frame_queue_nb_remaining(&is->subpq) > 0) {\n                    sp = frame_queue_peek(&is->subpq);\n\n                    if (frame_queue_nb_remaining(&is->subpq) > 1)\n                        sp2 = frame_queue_peek_next(&is->subpq);\n                    else\n                        sp2 = NULL;\n\n                    if (sp->serial != is->subtitleq.serial\n                            || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))\n                            || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))\n                    {\n                        if (sp->uploaded) {\n                            int i;\n                            for (i = 0; i < sp->sub.num_rects; i++) {\n                                AVSubtitleRect *sub_rect = sp->sub.rects[i];\n                                uint8_t *pixels;\n                                int pitch, j;\n\n                                if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)&pixels, &pitch)) {\n                                    for (j = 0; j < sub_rect->h; j++, pixels += pitch)\n                                        memset(pixels, 0, sub_rect->w << 2);\n                                    SDL_UnlockTexture(is->sub_texture);\n                                }\n                            }\n                        }\n                        frame_queue_next(&is->subpq);\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            frame_queue_next(&is->pictq);\n            is->force_refresh = 1;\n\n            if (is->step && !is->paused)\n                stream_toggle_pause(is);\n        }\ndisplay:\n        /* display picture */\n        if (!display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO && is->pictq.rindex_shown)\n            video_display(is);\n    }\n    is->force_refresh = 0;\n    if (show_status) {\n        AVBPrint buf;\n        static int64_t last_time;\n        int64_t cur_time;\n        int aqsize, vqsize, sqsize;\n        double av_diff;\n\n        cur_time = av_gettime_relative();\n        if (!last_time || (cur_time - last_time) >= 30000) {\n            aqsize = 0;\n            vqsize = 0;\n            sqsize = 0;\n            if (is->audio_st)\n                aqsize = is->audioq.size;\n            if (is->video_st)\n                vqsize = is->videoq.size;\n            if (is->subtitle_st)\n                sqsize = is->subtitleq.size;\n            av_diff = 0;\n            if (is->audio_st && is->video_st)\n                av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);\n            else if (is->video_st)\n                av_diff = get_master_clock(is) - get_clock(&is->vidclk);\n            else if (is->audio_st)\n                av_diff = get_master_clock(is) - get_clock(&is->audclk);\n\n            av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);\n            av_bprintf(&buf,\n                      \"%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%\"PRId64\"/%\"PRId64\"   \\r\",\n                      get_master_clock(is),\n                      (is->audio_st && is->video_st) ? \"A-V\" : (is->video_st ? \"M-V\" : (is->audio_st ? \"M-A\" : \"   \")),\n                      av_diff,\n                      is->frame_drops_early + is->frame_drops_late,\n                      aqsize / 1024,\n                      vqsize / 1024,\n                      sqsize,\n                      is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,\n                      is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);\n\n            if (show_status == 1 && AV_LOG_INFO > av_log_get_level())\n                fprintf(stderr, \"%s\", buf.str);\n            else\n                av_log(NULL, AV_LOG_INFO, \"%s\", buf.str);\n\n            fflush(stderr);\n            av_bprint_finalize(&buf, NULL);\n\n            last_time = cur_time;\n        }\n    }\n}\n\nstatic int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)\n{\n    Frame *vp;\n\n#if defined(DEBUG_SYNC)\n    printf(\"frame_type=%c pts=%0.3f\\n\",\n           av_get_picture_type_char(src_frame->pict_type), pts);\n#endif\n\n    if (!(vp = frame_queue_peek_writable(&is->pictq)))\n        return -1;\n\n    vp->sar = src_frame->sample_aspect_ratio;\n    vp->uploaded = 0;\n\n    vp->width = src_frame->width;\n    vp->height = src_frame->height;\n    vp->format = src_frame->format;\n\n    vp->pts = pts;\n    vp->duration = duration;\n    vp->pos = pos;\n    vp->serial = serial;\n\n    set_default_window_size(vp->width, vp->height, vp->sar);\n\n    av_frame_move_ref(vp->frame, src_frame);\n    frame_queue_push(&is->pictq);\n    return 0;\n}\n\nstatic int get_video_frame(VideoState *is, AVFrame *frame)\n{\n    int got_picture;\n\n    if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)\n        return -1;\n\n    if (got_picture) {\n        double dpts = NAN;\n\n        if (frame->pts != AV_NOPTS_VALUE)\n            dpts = av_q2d(is->video_st->time_base) * frame->pts;\n\n        frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);\n\n        if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {\n            if (frame->pts != AV_NOPTS_VALUE) {\n                double diff = dpts - get_master_clock(is);\n                if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&\n                    diff - is->frame_last_filter_delay < 0 &&\n                    is->viddec.pkt_serial == is->vidclk.serial &&\n                    is->videoq.nb_packets) {\n                    is->frame_drops_early++;\n                    av_frame_unref(frame);\n                    got_picture = 0;\n                }\n            }\n        }\n    }\n\n    return got_picture;\n}\n\n#if CONFIG_AVFILTER\nstatic int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,\n                                 AVFilterContext *source_ctx, AVFilterContext *sink_ctx)\n{\n    int ret, i;\n    int nb_filters = graph->nb_filters;\n    AVFilterInOut *outputs = NULL, *inputs = NULL;\n\n    if (filtergraph) {\n        outputs = avfilter_inout_alloc();\n        inputs  = avfilter_inout_alloc();\n        if (!outputs || !inputs) {\n            ret = AVERROR(ENOMEM);\n            goto fail;\n        }\n\n        outputs->name       = av_strdup(\"in\");\n        outputs->filter_ctx = source_ctx;\n        outputs->pad_idx    = 0;\n        outputs->next       = NULL;\n\n        inputs->name        = av_strdup(\"out\");\n        inputs->filter_ctx  = sink_ctx;\n        inputs->pad_idx     = 0;\n        inputs->next        = NULL;\n\n        if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)\n            goto fail;\n    } else {\n        if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)\n            goto fail;\n    }\n\n    /* Reorder the filters to ensure that inputs of the custom filters are merged first */\n    for (i = 0; i < graph->nb_filters - nb_filters; i++)\n        FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);\n\n    ret = avfilter_graph_config(graph, NULL);\nfail:\n    avfilter_inout_free(&outputs);\n    avfilter_inout_free(&inputs);\n    return ret;\n}\n\nstatic int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)\n{\n    enum AVPixelFormat pix_fmts[FF_ARRAY_ELEMS(sdl_texture_format_map)];\n    char sws_flags_str[512] = \"\";\n    char buffersrc_args[256];\n    int ret;\n    AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;\n    AVCodecParameters *codecpar = is->video_st->codecpar;\n    AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);\n    const AVDictionaryEntry *e = NULL;\n    int nb_pix_fmts = 0;\n    int i, j;\n\n    for (i = 0; i < renderer_info.num_texture_formats; i++) {\n        for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; j++) {\n            if (renderer_info.texture_formats[i] == sdl_texture_format_map[j].texture_fmt) {\n                pix_fmts[nb_pix_fmts++] = sdl_texture_format_map[j].format;\n                break;\n            }\n        }\n    }\n    pix_fmts[nb_pix_fmts] = AV_PIX_FMT_NONE;\n\n    while ((e = av_dict_get(sws_dict, \"\", e, AV_DICT_IGNORE_SUFFIX))) {\n        if (!strcmp(e->key, \"sws_flags\")) {\n            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), \"%s=%s:\", \"flags\", e->value);\n        } else\n            av_strlcatf(sws_flags_str, sizeof(sws_flags_str), \"%s=%s:\", e->key, e->value);\n    }\n    if (strlen(sws_flags_str))\n        sws_flags_str[strlen(sws_flags_str)-1] = '\\0';\n\n    graph->scale_sws_opts = av_strdup(sws_flags_str);\n\n    snprintf(buffersrc_args, sizeof(buffersrc_args),\n             \"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d\",\n             frame->width, frame->height, frame->format,\n             is->video_st->time_base.num, is->video_st->time_base.den,\n             codecpar->sample_aspect_ratio.num, FFMAX(codecpar->sample_aspect_ratio.den, 1));\n    if (fr.num && fr.den)\n        av_strlcatf(buffersrc_args, sizeof(buffersrc_args), \":frame_rate=%d/%d\", fr.num, fr.den);\n\n    if ((ret = avfilter_graph_create_filter(&filt_src,\n                                            avfilter_get_by_name(\"buffer\"),\n                                            \"ffplay_buffer\", buffersrc_args, NULL,\n                                            graph)) < 0)\n        goto fail;\n\n    ret = avfilter_graph_create_filter(&filt_out,\n                                       avfilter_get_by_name(\"buffersink\"),\n                                       \"ffplay_buffersink\", NULL, NULL, graph);\n    if (ret < 0)\n        goto fail;\n\n    if ((ret = av_opt_set_int_list(filt_out, \"pix_fmts\", pix_fmts,  AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto fail;\n\n    last_filter = filt_out;\n\n/* Note: this macro adds a filter before the lastly added filter, so the\n * processing order of the filters is in reverse */\n#define INSERT_FILT(name, arg) do {                                          \\\n    AVFilterContext *filt_ctx;                                               \\\n                                                                             \\\n    ret = avfilter_graph_create_filter(&filt_ctx,                            \\\n                                       avfilter_get_by_name(name),           \\\n                                       \"ffplay_\" name, arg, NULL, graph);    \\\n    if (ret < 0)                                                             \\\n        goto fail;                                                           \\\n                                                                             \\\n    ret = avfilter_link(filt_ctx, 0, last_filter, 0);                        \\\n    if (ret < 0)                                                             \\\n        goto fail;                                                           \\\n                                                                             \\\n    last_filter = filt_ctx;                                                  \\\n} while (0)\n\n    if (autorotate) {\n        int32_t *displaymatrix = (int32_t *)av_stream_get_side_data(is->video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL);\n        double theta = get_rotation(displaymatrix);\n\n        if (fabs(theta - 90) < 1.0) {\n            INSERT_FILT(\"transpose\", \"clock\");\n        } else if (fabs(theta - 180) < 1.0) {\n            INSERT_FILT(\"hflip\", NULL);\n            INSERT_FILT(\"vflip\", NULL);\n        } else if (fabs(theta - 270) < 1.0) {\n            INSERT_FILT(\"transpose\", \"cclock\");\n        } else if (fabs(theta) > 1.0) {\n            char rotate_buf[64];\n            snprintf(rotate_buf, sizeof(rotate_buf), \"%f*PI/180\", theta);\n            INSERT_FILT(\"rotate\", rotate_buf);\n        }\n    }\n\n    if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)\n        goto fail;\n\n    is->in_video_filter  = filt_src;\n    is->out_video_filter = filt_out;\n\nfail:\n    return ret;\n}\n\nstatic int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)\n{\n    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };\n    int sample_rates[2] = { 0, -1 };\n    AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;\n    char aresample_swr_opts[512] = \"\";\n    const AVDictionaryEntry *e = NULL;\n    AVBPrint bp;\n    char asrc_args[256];\n    int ret;\n\n    avfilter_graph_free(&is->agraph);\n    if (!(is->agraph = avfilter_graph_alloc()))\n        return AVERROR(ENOMEM);\n    is->agraph->nb_threads = filter_nbthreads;\n\n    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);\n\n    while ((e = av_dict_get(swr_opts, \"\", e, AV_DICT_IGNORE_SUFFIX)))\n        av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), \"%s=%s:\", e->key, e->value);\n    if (strlen(aresample_swr_opts))\n        aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\\0';\n    av_opt_set(is->agraph, \"aresample_swr_opts\", aresample_swr_opts, 0);\n\n    av_channel_layout_describe_bprint(&is->audio_filter_src.ch_layout, &bp);\n\n    ret = snprintf(asrc_args, sizeof(asrc_args),\n                   \"sample_rate=%d:sample_fmt=%s:time_base=%d/%d:channel_layout=%s\",\n                   is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),\n                   1, is->audio_filter_src.freq, bp.str);\n\n    ret = avfilter_graph_create_filter(&filt_asrc,\n                                       avfilter_get_by_name(\"abuffer\"), \"ffplay_abuffer\",\n                                       asrc_args, NULL, is->agraph);\n    if (ret < 0)\n        goto end;\n\n\n    ret = avfilter_graph_create_filter(&filt_asink,\n                                       avfilter_get_by_name(\"abuffersink\"), \"ffplay_abuffersink\",\n                                       NULL, NULL, is->agraph);\n    if (ret < 0)\n        goto end;\n\n    if ((ret = av_opt_set_int_list(filt_asink, \"sample_fmts\", sample_fmts,  AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto end;\n    if ((ret = av_opt_set_int(filt_asink, \"all_channel_counts\", 1, AV_OPT_SEARCH_CHILDREN)) < 0)\n        goto end;\n\n    if (force_output_format) {\n        sample_rates   [0] = is->audio_tgt.freq;\n        if ((ret = av_opt_set_int(filt_asink, \"all_channel_counts\", 0, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n        if ((ret = av_opt_set(filt_asink, \"ch_layouts\", bp.str, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n        if ((ret = av_opt_set_int_list(filt_asink, \"sample_rates\"   , sample_rates   ,  -1, AV_OPT_SEARCH_CHILDREN)) < 0)\n            goto end;\n    }\n\n\n    if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)\n        goto end;\n\n    is->in_audio_filter  = filt_asrc;\n    is->out_audio_filter = filt_asink;\n\nend:\n    if (ret < 0)\n        avfilter_graph_free(&is->agraph);\n    av_bprint_finalize(&bp, NULL);\n\n    return ret;\n}\n#endif  /* CONFIG_AVFILTER */\n\nstatic int audio_thread(void *arg)\n{\n    VideoState *is = arg;\n    AVFrame *frame = av_frame_alloc();\n    Frame *af;\n#if CONFIG_AVFILTER\n    int last_serial = -1;\n    int reconfigure;\n#endif\n    int got_frame = 0;\n    AVRational tb;\n    int ret = 0;\n\n    if (!frame)\n        return AVERROR(ENOMEM);\n\n    do {\n        if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)\n            goto the_end;\n\n        if (got_frame) {\n                tb = (AVRational){1, frame->sample_rate};\n\n#if CONFIG_AVFILTER\n                reconfigure =\n                    cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.ch_layout.nb_channels,\n                                   frame->format, frame->ch_layout.nb_channels)    ||\n                    av_channel_layout_compare(&is->audio_filter_src.ch_layout, &frame->ch_layout) ||\n                    is->audio_filter_src.freq           != frame->sample_rate ||\n                    is->auddec.pkt_serial               != last_serial;\n\n                if (reconfigure) {\n                    char buf1[1024], buf2[1024];\n                    av_channel_layout_describe(&is->audio_filter_src.ch_layout, buf1, sizeof(buf1));\n                    av_channel_layout_describe(&frame->ch_layout, buf2, sizeof(buf2));\n                    av_log(NULL, AV_LOG_DEBUG,\n                           \"Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\\n\",\n                           is->audio_filter_src.freq, is->audio_filter_src.ch_layout.nb_channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial,\n                           frame->sample_rate, frame->ch_layout.nb_channels, av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);\n\n                    is->audio_filter_src.fmt            = frame->format;\n                    ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &frame->ch_layout);\n                    if (ret < 0)\n                        goto the_end;\n                    is->audio_filter_src.freq           = frame->sample_rate;\n                    last_serial                         = is->auddec.pkt_serial;\n\n                    if ((ret = configure_audio_filters(is, afilters, 1)) < 0)\n                        goto the_end;\n                }\n\n            if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)\n                goto the_end;\n\n            while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {\n                tb = av_buffersink_get_time_base(is->out_audio_filter);\n#endif\n                if (!(af = frame_queue_peek_writable(&is->sampq)))\n                    goto the_end;\n\n                af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n                af->pos = frame->pkt_pos;\n                af->serial = is->auddec.pkt_serial;\n                af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});\n\n                av_frame_move_ref(af->frame, frame);\n                frame_queue_push(&is->sampq);\n\n#if CONFIG_AVFILTER\n                if (is->audioq.serial != is->auddec.pkt_serial)\n                    break;\n            }\n            if (ret == AVERROR_EOF)\n                is->auddec.finished = is->auddec.pkt_serial;\n#endif\n        }\n    } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);\n the_end:\n#if CONFIG_AVFILTER\n    avfilter_graph_free(&is->agraph);\n#endif\n    av_frame_free(&frame);\n    return ret;\n}\n\nstatic int decoder_start(Decoder *d, int (*fn)(void *), const char *thread_name, void* arg)\n{\n    packet_queue_start(d->queue);\n    d->decoder_tid = SDL_CreateThread(fn, thread_name, arg);\n    if (!d->decoder_tid) {\n        av_log(NULL, AV_LOG_ERROR, \"SDL_CreateThread(): %s\\n\", SDL_GetError());\n        return AVERROR(ENOMEM);\n    }\n    return 0;\n}\n\nstatic int video_thread(void *arg)\n{\n    VideoState *is = arg;\n    AVFrame *frame = av_frame_alloc();\n    double pts;\n    double duration;\n    int ret;\n    AVRational tb = is->video_st->time_base;\n    AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);\n\n#if CONFIG_AVFILTER\n    AVFilterGraph *graph = NULL;\n    AVFilterContext *filt_out = NULL, *filt_in = NULL;\n    int last_w = 0;\n    int last_h = 0;\n    enum AVPixelFormat last_format = -2;\n    int last_serial = -1;\n    int last_vfilter_idx = 0;\n#endif\n\n    if (!frame)\n        return AVERROR(ENOMEM);\n\n    for (;;) {\n        ret = get_video_frame(is, frame);\n        if (ret < 0)\n            goto the_end;\n        if (!ret)\n            continue;\n\n#if CONFIG_AVFILTER\n        if (   last_w != frame->width\n            || last_h != frame->height\n            || last_format != frame->format\n            || last_serial != is->viddec.pkt_serial\n            || last_vfilter_idx != is->vfilter_idx) {\n            av_log(NULL, AV_LOG_DEBUG,\n                   \"Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\\n\",\n                   last_w, last_h,\n                   (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), \"none\"), last_serial,\n                   frame->width, frame->height,\n                   (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), \"none\"), is->viddec.pkt_serial);\n            avfilter_graph_free(&graph);\n            graph = avfilter_graph_alloc();\n            if (!graph) {\n                ret = AVERROR(ENOMEM);\n                goto the_end;\n            }\n            graph->nb_threads = filter_nbthreads;\n            if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {\n                SDL_Event event;\n                event.type = FF_QUIT_EVENT;\n                event.user.data1 = is;\n                SDL_PushEvent(&event);\n                goto the_end;\n            }\n            filt_in  = is->in_video_filter;\n            filt_out = is->out_video_filter;\n            last_w = frame->width;\n            last_h = frame->height;\n            last_format = frame->format;\n            last_serial = is->viddec.pkt_serial;\n            last_vfilter_idx = is->vfilter_idx;\n            frame_rate = av_buffersink_get_frame_rate(filt_out);\n        }\n\n        ret = av_buffersrc_add_frame(filt_in, frame);\n        if (ret < 0)\n            goto the_end;\n\n        while (ret >= 0) {\n            is->frame_last_returned_time = av_gettime_relative() / 1000000.0;\n\n            ret = av_buffersink_get_frame_flags(filt_out, frame, 0);\n            if (ret < 0) {\n                if (ret == AVERROR_EOF)\n                    is->viddec.finished = is->viddec.pkt_serial;\n                ret = 0;\n                break;\n            }\n\n            is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;\n            if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)\n                is->frame_last_filter_delay = 0;\n            tb = av_buffersink_get_time_base(filt_out);\n#endif\n            duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);\n            pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);\n            ret = queue_picture(is, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial);\n            av_frame_unref(frame);\n#if CONFIG_AVFILTER\n            if (is->videoq.serial != is->viddec.pkt_serial)\n                break;\n        }\n#endif\n\n        if (ret < 0)\n            goto the_end;\n    }\n the_end:\n#if CONFIG_AVFILTER\n    avfilter_graph_free(&graph);\n#endif\n    av_frame_free(&frame);\n    return 0;\n}\n\nstatic int subtitle_thread(void *arg)\n{\n    VideoState *is = arg;\n    Frame *sp;\n    int got_subtitle;\n    double pts;\n\n    for (;;) {\n        if (!(sp = frame_queue_peek_writable(&is->subpq)))\n            return 0;\n\n        if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0)\n            break;\n\n        pts = 0;\n\n        if (got_subtitle && sp->sub.format == 0) {\n            if (sp->sub.pts != AV_NOPTS_VALUE)\n                pts = sp->sub.pts / (double)AV_TIME_BASE;\n            sp->pts = pts;\n            sp->serial = is->subdec.pkt_serial;\n            sp->width = is->subdec.avctx->width;\n            sp->height = is->subdec.avctx->height;\n            sp->uploaded = 0;\n\n            /* now we can update the picture count */\n            frame_queue_push(&is->subpq);\n        } else if (got_subtitle) {\n            avsubtitle_free(&sp->sub);\n        }\n    }\n    return 0;\n}\n\n/* copy samples for viewing in editor window */\nstatic void update_sample_display(VideoState *is, short *samples, int samples_size)\n{\n    int size, len;\n\n    size = samples_size / sizeof(short);\n    while (size > 0) {\n        len = SAMPLE_ARRAY_SIZE - is->sample_array_index;\n        if (len > size)\n            len = size;\n        memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));\n        samples += len;\n        is->sample_array_index += len;\n        if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)\n            is->sample_array_index = 0;\n        size -= len;\n    }\n}\n\n/* return the wanted number of samples to get better sync if sync_type is video\n * or external master clock */\nstatic int synchronize_audio(VideoState *is, int nb_samples)\n{\n    int wanted_nb_samples = nb_samples;\n\n    /* if not master, then we try to remove or add samples to correct the clock */\n    if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {\n        double diff, avg_diff;\n        int min_nb_samples, max_nb_samples;\n\n        diff = get_clock(&is->audclk) - get_master_clock(is);\n\n        if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {\n            is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;\n            if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {\n                /* not enough measures to have a correct estimate */\n                is->audio_diff_avg_count++;\n            } else {\n                /* estimate the A-V difference */\n                avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);\n\n                if (fabs(avg_diff) >= is->audio_diff_threshold) {\n                    wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);\n                    min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));\n                    max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));\n                    wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);\n                }\n                av_log(NULL, AV_LOG_TRACE, \"diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\\n\",\n                        diff, avg_diff, wanted_nb_samples - nb_samples,\n                        is->audio_clock, is->audio_diff_threshold);\n            }\n        } else {\n            /* too big difference : may be initial PTS errors, so\n               reset A-V filter */\n            is->audio_diff_avg_count = 0;\n            is->audio_diff_cum       = 0;\n        }\n    }\n\n    return wanted_nb_samples;\n}\n\n/**\n * Decode one audio frame and return its uncompressed size.\n *\n * The processed audio frame is decoded, converted if required, and\n * stored in is->audio_buf, with size in bytes given by the return\n * value.\n */\nstatic int audio_decode_frame(VideoState *is)\n{\n    int data_size, resampled_data_size;\n    av_unused double audio_clock0;\n    int wanted_nb_samples;\n    Frame *af;\n\n    if (is->paused)\n        return -1;\n\n    do {\n#if defined(_WIN32)\n        while (frame_queue_nb_remaining(&is->sampq) == 0) {\n            if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)\n                return -1;\n            av_usleep (1000);\n        }\n#endif\n        if (!(af = frame_queue_peek_readable(&is->sampq)))\n            return -1;\n        frame_queue_next(&is->sampq);\n    } while (af->serial != is->audioq.serial);\n\n    data_size = av_samples_get_buffer_size(NULL, af->frame->ch_layout.nb_channels,\n                                           af->frame->nb_samples,\n                                           af->frame->format, 1);\n\n    wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);\n\n    if (af->frame->format        != is->audio_src.fmt            ||\n        av_channel_layout_compare(&af->frame->ch_layout, &is->audio_src.ch_layout) ||\n        af->frame->sample_rate   != is->audio_src.freq           ||\n        (wanted_nb_samples       != af->frame->nb_samples && !is->swr_ctx)) {\n        swr_free(&is->swr_ctx);\n        swr_alloc_set_opts2(&is->swr_ctx,\n                            &is->audio_tgt.ch_layout, is->audio_tgt.fmt, is->audio_tgt.freq,\n                            &af->frame->ch_layout, af->frame->format, af->frame->sample_rate,\n                            0, NULL);\n        if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\\n\",\n                    af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->ch_layout.nb_channels,\n                    is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.ch_layout.nb_channels);\n            swr_free(&is->swr_ctx);\n            return -1;\n        }\n        if (av_channel_layout_copy(&is->audio_src.ch_layout, &af->frame->ch_layout) < 0)\n            return -1;\n        is->audio_src.freq = af->frame->sample_rate;\n        is->audio_src.fmt = af->frame->format;\n    }\n\n    if (is->swr_ctx) {\n        const uint8_t **in = (const uint8_t **)af->frame->extended_data;\n        uint8_t **out = &is->audio_buf1;\n        int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;\n        int out_size  = av_samples_get_buffer_size(NULL, is->audio_tgt.ch_layout.nb_channels, out_count, is->audio_tgt.fmt, 0);\n        int len2;\n        if (out_size < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"av_samples_get_buffer_size() failed\\n\");\n            return -1;\n        }\n        if (wanted_nb_samples != af->frame->nb_samples) {\n            if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,\n                                        wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"swr_set_compensation() failed\\n\");\n                return -1;\n            }\n        }\n        av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);\n        if (!is->audio_buf1)\n            return AVERROR(ENOMEM);\n        len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);\n        if (len2 < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"swr_convert() failed\\n\");\n            return -1;\n        }\n        if (len2 == out_count) {\n            av_log(NULL, AV_LOG_WARNING, \"audio buffer is probably too small\\n\");\n            if (swr_init(is->swr_ctx) < 0)\n                swr_free(&is->swr_ctx);\n        }\n        is->audio_buf = is->audio_buf1;\n        resampled_data_size = len2 * is->audio_tgt.ch_layout.nb_channels * av_get_bytes_per_sample(is->audio_tgt.fmt);\n    } else {\n        is->audio_buf = af->frame->data[0];\n        resampled_data_size = data_size;\n    }\n\n    audio_clock0 = is->audio_clock;\n    /* update the audio clock with the pts */\n    if (!isnan(af->pts))\n        is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;\n    else\n        is->audio_clock = NAN;\n    is->audio_clock_serial = af->serial;\n#ifdef DEBUG\n    {\n        static double last_clock;\n        printf(\"audio: delay=%0.3f clock=%0.3f clock0=%0.3f\\n\",\n               is->audio_clock - last_clock,\n               is->audio_clock, audio_clock0);\n        last_clock = is->audio_clock;\n    }\n#endif\n    return resampled_data_size;\n}\n\n/* prepare a new audio buffer */\nstatic void sdl_audio_callback(void *opaque, Uint8 *stream, int len)\n{\n    VideoState *is = opaque;\n    int audio_size, len1;\n\n    audio_callback_time = av_gettime_relative();\n\n    while (len > 0) {\n        if (is->audio_buf_index >= is->audio_buf_size) {\n           audio_size = audio_decode_frame(is);\n           if (audio_size < 0) {\n                /* if error, just output silence */\n               is->audio_buf = NULL;\n               is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;\n           } else {\n               if (is->show_mode != SHOW_MODE_VIDEO)\n                   update_sample_display(is, (int16_t *)is->audio_buf, audio_size);\n               is->audio_buf_size = audio_size;\n           }\n           is->audio_buf_index = 0;\n        }\n        len1 = is->audio_buf_size - is->audio_buf_index;\n        if (len1 > len)\n            len1 = len;\n        if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME)\n            memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);\n        else {\n            memset(stream, 0, len1);\n            if (!is->muted && is->audio_buf)\n                SDL_MixAudioFormat(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, is->audio_volume);\n        }\n        len -= len1;\n        stream += len1;\n        is->audio_buf_index += len1;\n    }\n    is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;\n    /* Let's assume the audio driver that is used by SDL has two periods. */\n    if (!isnan(is->audio_clock)) {\n        set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);\n        sync_clock_to_slave(&is->extclk, &is->audclk);\n    }\n}\n\nstatic int audio_open(void *opaque, AVChannelLayout *wanted_channel_layout, int wanted_sample_rate, struct AudioParams *audio_hw_params)\n{\n    SDL_AudioSpec wanted_spec, spec;\n    const char *env;\n    static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};\n    static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};\n    int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;\n    int wanted_nb_channels = wanted_channel_layout->nb_channels;\n\n    env = SDL_getenv(\"SDL_AUDIO_CHANNELS\");\n    if (env) {\n        wanted_nb_channels = atoi(env);\n        av_channel_layout_uninit(wanted_channel_layout);\n        av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);\n    }\n    if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {\n        av_channel_layout_uninit(wanted_channel_layout);\n        av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);\n    }\n    wanted_nb_channels = wanted_channel_layout->nb_channels;\n    wanted_spec.channels = wanted_nb_channels;\n    wanted_spec.freq = wanted_sample_rate;\n    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Invalid sample rate or channel count!\\n\");\n        return -1;\n    }\n    while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)\n        next_sample_rate_idx--;\n    wanted_spec.format = AUDIO_S16SYS;\n    wanted_spec.silence = 0;\n    wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));\n    wanted_spec.callback = sdl_audio_callback;\n    wanted_spec.userdata = opaque;\n    while (!(audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {\n        av_log(NULL, AV_LOG_WARNING, \"SDL_OpenAudio (%d channels, %d Hz): %s\\n\",\n               wanted_spec.channels, wanted_spec.freq, SDL_GetError());\n        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];\n        if (!wanted_spec.channels) {\n            wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];\n            wanted_spec.channels = wanted_nb_channels;\n            if (!wanted_spec.freq) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"No more combinations to try, audio open failed\\n\");\n                return -1;\n            }\n        }\n        av_channel_layout_default(wanted_channel_layout, wanted_spec.channels);\n    }\n    if (spec.format != AUDIO_S16SYS) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"SDL advised audio format %d is not supported!\\n\", spec.format);\n        return -1;\n    }\n    if (spec.channels != wanted_spec.channels) {\n        av_channel_layout_uninit(wanted_channel_layout);\n        av_channel_layout_default(wanted_channel_layout, spec.channels);\n        if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"SDL advised channel count %d is not supported!\\n\", spec.channels);\n            return -1;\n        }\n    }\n\n    audio_hw_params->fmt = AV_SAMPLE_FMT_S16;\n    audio_hw_params->freq = spec.freq;\n    if (av_channel_layout_copy(&audio_hw_params->ch_layout, wanted_channel_layout) < 0)\n        return -1;\n    audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, 1, audio_hw_params->fmt, 1);\n    audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, audio_hw_params->freq, audio_hw_params->fmt, 1);\n    if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {\n        av_log(NULL, AV_LOG_ERROR, \"av_samples_get_buffer_size failed\\n\");\n        return -1;\n    }\n    return spec.size;\n}\n\n/* open a given stream. Return 0 if OK */\nstatic int stream_component_open(VideoState *is, int stream_index)\n{\n    AVFormatContext *ic = is->ic;\n    AVCodecContext *avctx;\n    const AVCodec *codec;\n    const char *forced_codec_name = NULL;\n    AVDictionary *opts = NULL;\n    const AVDictionaryEntry *t = NULL;\n    int sample_rate;\n    AVChannelLayout ch_layout = { 0 };\n    int ret = 0;\n    int stream_lowres = lowres;\n\n    if (stream_index < 0 || stream_index >= ic->nb_streams)\n        return -1;\n\n    avctx = avcodec_alloc_context3(NULL);\n    if (!avctx)\n        return AVERROR(ENOMEM);\n\n    ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar);\n    if (ret < 0)\n        goto fail;\n    avctx->pkt_timebase = ic->streams[stream_index]->time_base;\n\n    codec = avcodec_find_decoder(avctx->codec_id);\n\n    switch(avctx->codec_type){\n        case AVMEDIA_TYPE_AUDIO   : is->last_audio_stream    = stream_index; forced_codec_name =    audio_codec_name; break;\n        case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;\n        case AVMEDIA_TYPE_VIDEO   : is->last_video_stream    = stream_index; forced_codec_name =    video_codec_name; break;\n    }\n    if (forced_codec_name)\n        codec = avcodec_find_decoder_by_name(forced_codec_name);\n    if (!codec) {\n        if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,\n                                      \"No codec could be found with name '%s'\\n\", forced_codec_name);\n        else                   av_log(NULL, AV_LOG_WARNING,\n                                      \"No decoder could be found for codec %s\\n\", avcodec_get_name(avctx->codec_id));\n        ret = AVERROR(EINVAL);\n        goto fail;\n    }\n\n    avctx->codec_id = codec->id;\n    if (stream_lowres > codec->max_lowres) {\n        av_log(avctx, AV_LOG_WARNING, \"The maximum value for lowres supported by the decoder is %d\\n\",\n                codec->max_lowres);\n        stream_lowres = codec->max_lowres;\n    }\n    avctx->lowres = stream_lowres;\n\n    if (fast)\n        avctx->flags2 |= AV_CODEC_FLAG2_FAST;\n\n    opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);\n    if (!av_dict_get(opts, \"threads\", NULL, 0))\n        av_dict_set(&opts, \"threads\", \"auto\", 0);\n    if (stream_lowres)\n        av_dict_set_int(&opts, \"lowres\", stream_lowres, 0);\n    if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) {\n        goto fail;\n    }\n    if ((t = av_dict_get(opts, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(NULL, AV_LOG_ERROR, \"Option %s not found.\\n\", t->key);\n        ret =  AVERROR_OPTION_NOT_FOUND;\n        goto fail;\n    }\n\n    is->eof = 0;\n    ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;\n    switch (avctx->codec_type) {\n    case AVMEDIA_TYPE_AUDIO:\n#if CONFIG_AVFILTER\n        {\n            AVFilterContext *sink;\n\n            is->audio_filter_src.freq           = avctx->sample_rate;\n            ret = av_channel_layout_copy(&is->audio_filter_src.ch_layout, &avctx->ch_layout);\n            if (ret < 0)\n                goto fail;\n            is->audio_filter_src.fmt            = avctx->sample_fmt;\n            if ((ret = configure_audio_filters(is, afilters, 0)) < 0)\n                goto fail;\n            sink = is->out_audio_filter;\n            sample_rate    = av_buffersink_get_sample_rate(sink);\n            ret = av_buffersink_get_ch_layout(sink, &ch_layout);\n            if (ret < 0)\n                goto fail;\n        }\n#else\n        sample_rate    = avctx->sample_rate;\n        ret = av_channel_layout_copy(&ch_layout, &avctx->ch_layout);\n        if (ret < 0)\n            goto fail;\n#endif\n\n        /* prepare audio output */\n        if ((ret = audio_open(is, &ch_layout, sample_rate, &is->audio_tgt)) < 0)\n            goto fail;\n        is->audio_hw_buf_size = ret;\n        is->audio_src = is->audio_tgt;\n        is->audio_buf_size  = 0;\n        is->audio_buf_index = 0;\n\n        /* init averaging filter */\n        is->audio_diff_avg_coef  = exp(log(0.01) / AUDIO_DIFF_AVG_NB);\n        is->audio_diff_avg_count = 0;\n        /* since we do not have a precise anough audio FIFO fullness,\n           we correct audio sync only if larger than this threshold */\n        is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec;\n\n        is->audio_stream = stream_index;\n        is->audio_st = ic->streams[stream_index];\n\n        if ((ret = decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread)) < 0)\n            goto fail;\n        if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) {\n            is->auddec.start_pts = is->audio_st->start_time;\n            is->auddec.start_pts_tb = is->audio_st->time_base;\n        }\n        if ((ret = decoder_start(&is->auddec, audio_thread, \"audio_decoder\", is)) < 0)\n            goto out;\n        SDL_PauseAudioDevice(audio_dev, 0);\n        break;\n    case AVMEDIA_TYPE_VIDEO:\n        is->video_stream = stream_index;\n        is->video_st = ic->streams[stream_index];\n\n        if ((ret = decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread)) < 0)\n            goto fail;\n        if ((ret = decoder_start(&is->viddec, video_thread, \"video_decoder\", is)) < 0)\n            goto out;\n        is->queue_attachments_req = 1;\n        break;\n    case AVMEDIA_TYPE_SUBTITLE:\n        is->subtitle_stream = stream_index;\n        is->subtitle_st = ic->streams[stream_index];\n\n        if ((ret = decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread)) < 0)\n            goto fail;\n        if ((ret = decoder_start(&is->subdec, subtitle_thread, \"subtitle_decoder\", is)) < 0)\n            goto out;\n        break;\n    default:\n        break;\n    }\n    goto out;\n\nfail:\n    avcodec_free_context(&avctx);\nout:\n    av_channel_layout_uninit(&ch_layout);\n    av_dict_free(&opts);\n\n    return ret;\n}\n\nstatic int decode_interrupt_cb(void *ctx)\n{\n    VideoState *is = ctx;\n    return is->abort_request;\n}\n\nstatic int stream_has_enough_packets(AVStream *st, int stream_id, PacketQueue *queue) {\n    return stream_id < 0 ||\n           queue->abort_request ||\n           (st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||\n           queue->nb_packets > MIN_FRAMES && (!queue->duration || av_q2d(st->time_base) * queue->duration > 1.0);\n}\n\nstatic int is_realtime(AVFormatContext *s)\n{\n    if(   !strcmp(s->iformat->name, \"rtp\")\n       || !strcmp(s->iformat->name, \"rtsp\")\n       || !strcmp(s->iformat->name, \"sdp\")\n    )\n        return 1;\n\n    if(s->pb && (   !strncmp(s->url, \"rtp:\", 4)\n                 || !strncmp(s->url, \"udp:\", 4)\n                )\n    )\n        return 1;\n    return 0;\n}\n\n/* this thread gets the stream from the disk or the network */\nstatic int read_thread(void *arg)\n{\n    VideoState *is = arg;\n    AVFormatContext *ic = NULL;\n    int err, i, ret;\n    int st_index[AVMEDIA_TYPE_NB];\n    AVPacket *pkt = NULL;\n    int64_t stream_start_time;\n    int pkt_in_play_range = 0;\n    const AVDictionaryEntry *t;\n    SDL_mutex *wait_mutex = SDL_CreateMutex();\n    int scan_all_pmts_set = 0;\n    int64_t pkt_ts;\n\n    if (!wait_mutex) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateMutex(): %s\\n\", SDL_GetError());\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    memset(st_index, -1, sizeof(st_index));\n    is->eof = 0;\n\n    pkt = av_packet_alloc();\n    if (!pkt) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not allocate packet.\\n\");\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n    ic = avformat_alloc_context();\n    if (!ic) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not allocate context.\\n\");\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n    ic->interrupt_callback.callback = decode_interrupt_cb;\n    ic->interrupt_callback.opaque = is;\n    if (!av_dict_get(format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE)) {\n        av_dict_set(&format_opts, \"scan_all_pmts\", \"1\", AV_DICT_DONT_OVERWRITE);\n        scan_all_pmts_set = 1;\n    }\n    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);\n    if (err < 0) {\n        print_error(is->filename, err);\n        ret = -1;\n        goto fail;\n    }\n    if (scan_all_pmts_set)\n        av_dict_set(&format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE);\n\n    if ((t = av_dict_get(format_opts, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n        av_log(NULL, AV_LOG_ERROR, \"Option %s not found.\\n\", t->key);\n        ret = AVERROR_OPTION_NOT_FOUND;\n        goto fail;\n    }\n    is->ic = ic;\n\n    if (genpts)\n        ic->flags |= AVFMT_FLAG_GENPTS;\n\n    av_format_inject_global_side_data(ic);\n\n    if (find_stream_info) {\n        AVDictionary **opts = setup_find_stream_info_opts(ic, codec_opts);\n        int orig_nb_streams = ic->nb_streams;\n\n        err = avformat_find_stream_info(ic, opts);\n\n        for (i = 0; i < orig_nb_streams; i++)\n            av_dict_free(&opts[i]);\n        av_freep(&opts);\n\n        if (err < 0) {\n            av_log(NULL, AV_LOG_WARNING,\n                   \"%s: could not find codec parameters\\n\", is->filename);\n            ret = -1;\n            goto fail;\n        }\n    }\n\n    if (ic->pb)\n        ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end\n\n    if (seek_by_bytes < 0)\n        seek_by_bytes = !(ic->iformat->flags & AVFMT_NO_BYTE_SEEK) &&\n                        !!(ic->iformat->flags & AVFMT_TS_DISCONT) &&\n                        strcmp(\"ogg\", ic->iformat->name);\n\n    is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;\n\n    if (!window_title && (t = av_dict_get(ic->metadata, \"title\", NULL, 0)))\n        window_title = av_asprintf(\"%s - %s\", t->value, input_filename);\n\n    /* if seeking requested, we execute it */\n    if (start_time != AV_NOPTS_VALUE) {\n        int64_t timestamp;\n\n        timestamp = start_time;\n        /* add the stream start time */\n        if (ic->start_time != AV_NOPTS_VALUE)\n            timestamp += ic->start_time;\n        ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_WARNING, \"%s: could not seek to position %0.3f\\n\",\n                    is->filename, (double)timestamp / AV_TIME_BASE);\n        }\n    }\n\n    is->realtime = is_realtime(ic);\n\n    if (show_status)\n        av_dump_format(ic, 0, is->filename, 0);\n\n    for (i = 0; i < ic->nb_streams; i++) {\n        AVStream *st = ic->streams[i];\n        enum AVMediaType type = st->codecpar->codec_type;\n        st->discard = AVDISCARD_ALL;\n        if (type >= 0 && wanted_stream_spec[type] && st_index[type] == -1)\n            if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)\n                st_index[type] = i;\n    }\n    for (i = 0; i < AVMEDIA_TYPE_NB; i++) {\n        if (wanted_stream_spec[i] && st_index[i] == -1) {\n            av_log(NULL, AV_LOG_ERROR, \"Stream specifier %s does not match any %s stream\\n\", wanted_stream_spec[i], av_get_media_type_string(i));\n            st_index[i] = INT_MAX;\n        }\n    }\n\n    if (!video_disable)\n        st_index[AVMEDIA_TYPE_VIDEO] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,\n                                st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);\n    if (!audio_disable)\n        st_index[AVMEDIA_TYPE_AUDIO] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,\n                                st_index[AVMEDIA_TYPE_AUDIO],\n                                st_index[AVMEDIA_TYPE_VIDEO],\n                                NULL, 0);\n    if (!video_disable && !subtitle_disable)\n        st_index[AVMEDIA_TYPE_SUBTITLE] =\n            av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,\n                                st_index[AVMEDIA_TYPE_SUBTITLE],\n                                (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?\n                                 st_index[AVMEDIA_TYPE_AUDIO] :\n                                 st_index[AVMEDIA_TYPE_VIDEO]),\n                                NULL, 0);\n\n    is->show_mode = show_mode;\n    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {\n        AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];\n        AVCodecParameters *codecpar = st->codecpar;\n        AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);\n        if (codecpar->width)\n            set_default_window_size(codecpar->width, codecpar->height, sar);\n    }\n\n    /* open the streams */\n    if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {\n        stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);\n    }\n\n    ret = -1;\n    if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {\n        ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);\n    }\n    if (is->show_mode == SHOW_MODE_NONE)\n        is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;\n\n    if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {\n        stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);\n    }\n\n    if (is->video_stream < 0 && is->audio_stream < 0) {\n        av_log(NULL, AV_LOG_FATAL, \"Failed to open file '%s' or configure filtergraph\\n\",\n               is->filename);\n        ret = -1;\n        goto fail;\n    }\n\n    if (infinite_buffer < 0 && is->realtime)\n        infinite_buffer = 1;\n\n    for (;;) {\n        if (is->abort_request)\n            break;\n        if (is->paused != is->last_paused) {\n            is->last_paused = is->paused;\n            if (is->paused)\n                is->read_pause_return = av_read_pause(ic);\n            else\n                av_read_play(ic);\n        }\n#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL\n        if (is->paused &&\n                (!strcmp(ic->iformat->name, \"rtsp\") ||\n                 (ic->pb && !strncmp(input_filename, \"mmsh:\", 5)))) {\n            /* wait 10 ms to avoid trying to get another packet */\n            /* XXX: horrible */\n            SDL_Delay(10);\n            continue;\n        }\n#endif\n        if (is->seek_req) {\n            int64_t seek_target = is->seek_pos;\n            int64_t seek_min    = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;\n            int64_t seek_max    = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;\n// FIXME the +-2 is due to rounding being not done in the correct direction in generation\n//      of the seek_pos/seek_rel variables\n\n            ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);\n            if (ret < 0) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"%s: error while seeking\\n\", is->ic->url);\n            } else {\n                if (is->audio_stream >= 0)\n                    packet_queue_flush(&is->audioq);\n                if (is->subtitle_stream >= 0)\n                    packet_queue_flush(&is->subtitleq);\n                if (is->video_stream >= 0)\n                    packet_queue_flush(&is->videoq);\n                if (is->seek_flags & AVSEEK_FLAG_BYTE) {\n                   set_clock(&is->extclk, NAN, 0);\n                } else {\n                   set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);\n                }\n            }\n            is->seek_req = 0;\n            is->queue_attachments_req = 1;\n            is->eof = 0;\n            if (is->paused)\n                step_to_next_frame(is);\n        }\n        if (is->queue_attachments_req) {\n            if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {\n                if ((ret = av_packet_ref(pkt, &is->video_st->attached_pic)) < 0)\n                    goto fail;\n                packet_queue_put(&is->videoq, pkt);\n                packet_queue_put_nullpacket(&is->videoq, pkt, is->video_stream);\n            }\n            is->queue_attachments_req = 0;\n        }\n\n        /* if the queue are full, no need to read more */\n        if (infinite_buffer<1 &&\n              (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE\n            || (stream_has_enough_packets(is->audio_st, is->audio_stream, &is->audioq) &&\n                stream_has_enough_packets(is->video_st, is->video_stream, &is->videoq) &&\n                stream_has_enough_packets(is->subtitle_st, is->subtitle_stream, &is->subtitleq)))) {\n            /* wait 10 ms */\n            SDL_LockMutex(wait_mutex);\n            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);\n            SDL_UnlockMutex(wait_mutex);\n            continue;\n        }\n        if (!is->paused &&\n            (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&\n            (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {\n            if (loop != 1 && (!loop || --loop)) {\n                stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);\n            } else if (autoexit) {\n                ret = AVERROR_EOF;\n                goto fail;\n            }\n        }\n        ret = av_read_frame(ic, pkt);\n        if (ret < 0) {\n            if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {\n                if (is->video_stream >= 0)\n                    packet_queue_put_nullpacket(&is->videoq, pkt, is->video_stream);\n                if (is->audio_stream >= 0)\n                    packet_queue_put_nullpacket(&is->audioq, pkt, is->audio_stream);\n                if (is->subtitle_stream >= 0)\n                    packet_queue_put_nullpacket(&is->subtitleq, pkt, is->subtitle_stream);\n                is->eof = 1;\n            }\n            if (ic->pb && ic->pb->error) {\n                if (autoexit)\n                    goto fail;\n                else\n                    break;\n            }\n            SDL_LockMutex(wait_mutex);\n            SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);\n            SDL_UnlockMutex(wait_mutex);\n            continue;\n        } else {\n            is->eof = 0;\n        }\n        /* check if packet is in play range specified by user, then queue, otherwise discard */\n        stream_start_time = ic->streams[pkt->stream_index]->start_time;\n        pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;\n        pkt_in_play_range = duration == AV_NOPTS_VALUE ||\n                (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *\n                av_q2d(ic->streams[pkt->stream_index]->time_base) -\n                (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000\n                <= ((double)duration / 1000000);\n        if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {\n            packet_queue_put(&is->audioq, pkt);\n        } else if (pkt->stream_index == is->video_stream && pkt_in_play_range\n                   && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {\n            packet_queue_put(&is->videoq, pkt);\n        } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {\n            packet_queue_put(&is->subtitleq, pkt);\n        } else {\n            av_packet_unref(pkt);\n        }\n    }\n\n    ret = 0;\n fail:\n    if (ic && !is->ic)\n        avformat_close_input(&ic);\n\n    av_packet_free(&pkt);\n    if (ret != 0) {\n        SDL_Event event;\n\n        event.type = FF_QUIT_EVENT;\n        event.user.data1 = is;\n        SDL_PushEvent(&event);\n    }\n    SDL_DestroyMutex(wait_mutex);\n    return 0;\n}\n\nstatic VideoState *stream_open(const char *filename,\n                               const AVInputFormat *iformat)\n{\n    VideoState *is;\n\n    is = av_mallocz(sizeof(VideoState));\n    if (!is)\n        return NULL;\n    is->last_video_stream = is->video_stream = -1;\n    is->last_audio_stream = is->audio_stream = -1;\n    is->last_subtitle_stream = is->subtitle_stream = -1;\n    is->filename = av_strdup(filename);\n    if (!is->filename)\n        goto fail;\n    is->iformat = iformat;\n    is->ytop    = 0;\n    is->xleft   = 0;\n\n    /* start video display */\n    if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)\n        goto fail;\n    if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)\n        goto fail;\n    if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)\n        goto fail;\n\n    if (packet_queue_init(&is->videoq) < 0 ||\n        packet_queue_init(&is->audioq) < 0 ||\n        packet_queue_init(&is->subtitleq) < 0)\n        goto fail;\n\n    if (!(is->continue_read_thread = SDL_CreateCond())) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateCond(): %s\\n\", SDL_GetError());\n        goto fail;\n    }\n\n    init_clock(&is->vidclk, &is->videoq.serial);\n    init_clock(&is->audclk, &is->audioq.serial);\n    init_clock(&is->extclk, &is->extclk.serial);\n    is->audio_clock_serial = -1;\n    if (startup_volume < 0)\n        av_log(NULL, AV_LOG_WARNING, \"-volume=%d < 0, setting to 0\\n\", startup_volume);\n    if (startup_volume > 100)\n        av_log(NULL, AV_LOG_WARNING, \"-volume=%d > 100, setting to 100\\n\", startup_volume);\n    startup_volume = av_clip(startup_volume, 0, 100);\n    startup_volume = av_clip(SDL_MIX_MAXVOLUME * startup_volume / 100, 0, SDL_MIX_MAXVOLUME);\n    is->audio_volume = startup_volume;\n    is->muted = 0;\n    is->av_sync_type = av_sync_type;\n    is->read_tid     = SDL_CreateThread(read_thread, \"read_thread\", is);\n    if (!is->read_tid) {\n        av_log(NULL, AV_LOG_FATAL, \"SDL_CreateThread(): %s\\n\", SDL_GetError());\nfail:\n        stream_close(is);\n        return NULL;\n    }\n    return is;\n}\n\nstatic void stream_cycle_channel(VideoState *is, int codec_type)\n{\n    AVFormatContext *ic = is->ic;\n    int start_index, stream_index;\n    int old_index;\n    AVStream *st;\n    AVProgram *p = NULL;\n    int nb_streams = is->ic->nb_streams;\n\n    if (codec_type == AVMEDIA_TYPE_VIDEO) {\n        start_index = is->last_video_stream;\n        old_index = is->video_stream;\n    } else if (codec_type == AVMEDIA_TYPE_AUDIO) {\n        start_index = is->last_audio_stream;\n        old_index = is->audio_stream;\n    } else {\n        start_index = is->last_subtitle_stream;\n        old_index = is->subtitle_stream;\n    }\n    stream_index = start_index;\n\n    if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {\n        p = av_find_program_from_stream(ic, NULL, is->video_stream);\n        if (p) {\n            nb_streams = p->nb_stream_indexes;\n            for (start_index = 0; start_index < nb_streams; start_index++)\n                if (p->stream_index[start_index] == stream_index)\n                    break;\n            if (start_index == nb_streams)\n                start_index = -1;\n            stream_index = start_index;\n        }\n    }\n\n    for (;;) {\n        if (++stream_index >= nb_streams)\n        {\n            if (codec_type == AVMEDIA_TYPE_SUBTITLE)\n            {\n                stream_index = -1;\n                is->last_subtitle_stream = -1;\n                goto the_end;\n            }\n            if (start_index == -1)\n                return;\n            stream_index = 0;\n        }\n        if (stream_index == start_index)\n            return;\n        st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];\n        if (st->codecpar->codec_type == codec_type) {\n            /* check that parameters are OK */\n            switch (codec_type) {\n            case AVMEDIA_TYPE_AUDIO:\n                if (st->codecpar->sample_rate != 0 &&\n                    st->codecpar->ch_layout.nb_channels != 0)\n                    goto the_end;\n                break;\n            case AVMEDIA_TYPE_VIDEO:\n            case AVMEDIA_TYPE_SUBTITLE:\n                goto the_end;\n            default:\n                break;\n            }\n        }\n    }\n the_end:\n    if (p && stream_index != -1)\n        stream_index = p->stream_index[stream_index];\n    av_log(NULL, AV_LOG_INFO, \"Switch %s stream from #%d to #%d\\n\",\n           av_get_media_type_string(codec_type),\n           old_index,\n           stream_index);\n\n    stream_component_close(is, old_index);\n    stream_component_open(is, stream_index);\n}\n\n\nstatic void toggle_full_screen(VideoState *is)\n{\n    is_full_screen = !is_full_screen;\n    SDL_SetWindowFullscreen(window, is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);\n}\n\nstatic void toggle_audio_display(VideoState *is)\n{\n    int next = is->show_mode;\n    do {\n        next = (next + 1) % SHOW_MODE_NB;\n    } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));\n    if (is->show_mode != next) {\n        is->force_refresh = 1;\n        is->show_mode = next;\n    }\n}\n\nstatic void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {\n    double remaining_time = 0.0;\n    SDL_PumpEvents();\n    while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {\n        if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {\n            SDL_ShowCursor(0);\n            cursor_hidden = 1;\n        }\n        if (remaining_time > 0.0)\n            av_usleep((int64_t)(remaining_time * 1000000.0));\n        remaining_time = REFRESH_RATE;\n        if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))\n            video_refresh(is, &remaining_time);\n        SDL_PumpEvents();\n    }\n}\n\nstatic void seek_chapter(VideoState *is, int incr)\n{\n    int64_t pos = get_master_clock(is) * AV_TIME_BASE;\n    int i;\n\n    if (!is->ic->nb_chapters)\n        return;\n\n    /* find the current chapter */\n    for (i = 0; i < is->ic->nb_chapters; i++) {\n        AVChapter *ch = is->ic->chapters[i];\n        if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {\n            i--;\n            break;\n        }\n    }\n\n    i += incr;\n    i = FFMAX(i, 0);\n    if (i >= is->ic->nb_chapters)\n        return;\n\n    av_log(NULL, AV_LOG_VERBOSE, \"Seeking to chapter %d.\\n\", i);\n    stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,\n                                 AV_TIME_BASE_Q), 0, 0);\n}\n\n/* handle an event sent by the GUI */\nstatic void event_loop(VideoState *cur_stream)\n{\n    SDL_Event event;\n    double incr, pos, frac;\n\n    for (;;) {\n        double x;\n        refresh_loop_wait_event(cur_stream, &event);\n        switch (event.type) {\n        case SDL_KEYDOWN:\n            if (exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) {\n                do_exit(cur_stream);\n                break;\n            }\n            // If we don't yet have a window, skip all key events, because read_thread might still be initializing...\n            if (!cur_stream->width)\n                continue;\n            switch (event.key.keysym.sym) {\n            case SDLK_f:\n                toggle_full_screen(cur_stream);\n                cur_stream->force_refresh = 1;\n                break;\n            case SDLK_p:\n            case SDLK_SPACE:\n                toggle_pause(cur_stream);\n                break;\n            case SDLK_m:\n                toggle_mute(cur_stream);\n                break;\n            case SDLK_KP_MULTIPLY:\n            case SDLK_0:\n                update_volume(cur_stream, 1, SDL_VOLUME_STEP);\n                break;\n            case SDLK_KP_DIVIDE:\n            case SDLK_9:\n                update_volume(cur_stream, -1, SDL_VOLUME_STEP);\n                break;\n            case SDLK_s: // S: Step to next frame\n                step_to_next_frame(cur_stream);\n                break;\n            case SDLK_a:\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);\n                break;\n            case SDLK_v:\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);\n                break;\n            case SDLK_c:\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);\n                break;\n            case SDLK_t:\n                stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);\n                break;\n            case SDLK_w:\n#if CONFIG_AVFILTER\n                if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {\n                    if (++cur_stream->vfilter_idx >= nb_vfilters)\n                        cur_stream->vfilter_idx = 0;\n                } else {\n                    cur_stream->vfilter_idx = 0;\n                    toggle_audio_display(cur_stream);\n                }\n#else\n                toggle_audio_display(cur_stream);\n#endif\n                break;\n            case SDLK_PAGEUP:\n                if (cur_stream->ic->nb_chapters <= 1) {\n                    incr = 600.0;\n                    goto do_seek;\n                }\n                seek_chapter(cur_stream, 1);\n                break;\n            case SDLK_PAGEDOWN:\n                if (cur_stream->ic->nb_chapters <= 1) {\n                    incr = -600.0;\n                    goto do_seek;\n                }\n                seek_chapter(cur_stream, -1);\n                break;\n            case SDLK_LEFT:\n                incr = seek_interval ? -seek_interval : -10.0;\n                goto do_seek;\n            case SDLK_RIGHT:\n                incr = seek_interval ? seek_interval : 10.0;\n                goto do_seek;\n            case SDLK_UP:\n                incr = 60.0;\n                goto do_seek;\n            case SDLK_DOWN:\n                incr = -60.0;\n            do_seek:\n                    if (seek_by_bytes) {\n                        pos = -1;\n                        if (pos < 0 && cur_stream->video_stream >= 0)\n                            pos = frame_queue_last_pos(&cur_stream->pictq);\n                        if (pos < 0 && cur_stream->audio_stream >= 0)\n                            pos = frame_queue_last_pos(&cur_stream->sampq);\n                        if (pos < 0)\n                            pos = avio_tell(cur_stream->ic->pb);\n                        if (cur_stream->ic->bit_rate)\n                            incr *= cur_stream->ic->bit_rate / 8.0;\n                        else\n                            incr *= 180000.0;\n                        pos += incr;\n                        stream_seek(cur_stream, pos, incr, 1);\n                    } else {\n                        pos = get_master_clock(cur_stream);\n                        if (isnan(pos))\n                            pos = (double)cur_stream->seek_pos / AV_TIME_BASE;\n                        pos += incr;\n                        if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)\n                            pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;\n                        stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);\n                    }\n                break;\n            default:\n                break;\n            }\n            break;\n        case SDL_MOUSEBUTTONDOWN:\n            if (exit_on_mousedown) {\n                do_exit(cur_stream);\n                break;\n            }\n            if (event.button.button == SDL_BUTTON_LEFT) {\n                static int64_t last_mouse_left_click = 0;\n                if (av_gettime_relative() - last_mouse_left_click <= 500000) {\n                    toggle_full_screen(cur_stream);\n                    cur_stream->force_refresh = 1;\n                    last_mouse_left_click = 0;\n                } else {\n                    last_mouse_left_click = av_gettime_relative();\n                }\n            }\n        case SDL_MOUSEMOTION:\n            if (cursor_hidden) {\n                SDL_ShowCursor(1);\n                cursor_hidden = 0;\n            }\n            cursor_last_shown = av_gettime_relative();\n            if (event.type == SDL_MOUSEBUTTONDOWN) {\n                if (event.button.button != SDL_BUTTON_RIGHT)\n                    break;\n                x = event.button.x;\n            } else {\n                if (!(event.motion.state & SDL_BUTTON_RMASK))\n                    break;\n                x = event.motion.x;\n            }\n                if (seek_by_bytes || cur_stream->ic->duration <= 0) {\n                    uint64_t size =  avio_size(cur_stream->ic->pb);\n                    stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);\n                } else {\n                    int64_t ts;\n                    int ns, hh, mm, ss;\n                    int tns, thh, tmm, tss;\n                    tns  = cur_stream->ic->duration / 1000000LL;\n                    thh  = tns / 3600;\n                    tmm  = (tns % 3600) / 60;\n                    tss  = (tns % 60);\n                    frac = x / cur_stream->width;\n                    ns   = frac * tns;\n                    hh   = ns / 3600;\n                    mm   = (ns % 3600) / 60;\n                    ss   = (ns % 60);\n                    av_log(NULL, AV_LOG_INFO,\n                           \"Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \\n\", frac*100,\n                            hh, mm, ss, thh, tmm, tss);\n                    ts = frac * cur_stream->ic->duration;\n                    if (cur_stream->ic->start_time != AV_NOPTS_VALUE)\n                        ts += cur_stream->ic->start_time;\n                    stream_seek(cur_stream, ts, 0, 0);\n                }\n            break;\n        case SDL_WINDOWEVENT:\n            switch (event.window.event) {\n                case SDL_WINDOWEVENT_SIZE_CHANGED:\n                    screen_width  = cur_stream->width  = event.window.data1;\n                    screen_height = cur_stream->height = event.window.data2;\n                    if (cur_stream->vis_texture) {\n                        SDL_DestroyTexture(cur_stream->vis_texture);\n                        cur_stream->vis_texture = NULL;\n                    }\n                case SDL_WINDOWEVENT_EXPOSED:\n                    cur_stream->force_refresh = 1;\n            }\n            break;\n        case SDL_QUIT:\n        case FF_QUIT_EVENT:\n            do_exit(cur_stream);\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nstatic int opt_width(void *optctx, const char *opt, const char *arg)\n{\n    screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);\n    return 0;\n}\n\nstatic int opt_height(void *optctx, const char *opt, const char *arg)\n{\n    screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);\n    return 0;\n}\n\nstatic int opt_format(void *optctx, const char *opt, const char *arg)\n{\n    file_iformat = av_find_input_format(arg);\n    if (!file_iformat) {\n        av_log(NULL, AV_LOG_FATAL, \"Unknown input format: %s\\n\", arg);\n        return AVERROR(EINVAL);\n    }\n    return 0;\n}\n\nstatic int opt_sync(void *optctx, const char *opt, const char *arg)\n{\n    if (!strcmp(arg, \"audio\"))\n        av_sync_type = AV_SYNC_AUDIO_MASTER;\n    else if (!strcmp(arg, \"video\"))\n        av_sync_type = AV_SYNC_VIDEO_MASTER;\n    else if (!strcmp(arg, \"ext\"))\n        av_sync_type = AV_SYNC_EXTERNAL_CLOCK;\n    else {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown value for %s: %s\\n\", opt, arg);\n        exit(1);\n    }\n    return 0;\n}\n\nstatic int opt_seek(void *optctx, const char *opt, const char *arg)\n{\n    start_time = parse_time_or_die(opt, arg, 1);\n    return 0;\n}\n\nstatic int opt_duration(void *optctx, const char *opt, const char *arg)\n{\n    duration = parse_time_or_die(opt, arg, 1);\n    return 0;\n}\n\nstatic int opt_show_mode(void *optctx, const char *opt, const char *arg)\n{\n    show_mode = !strcmp(arg, \"video\") ? SHOW_MODE_VIDEO :\n                !strcmp(arg, \"waves\") ? SHOW_MODE_WAVES :\n                !strcmp(arg, \"rdft\" ) ? SHOW_MODE_RDFT  :\n                parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);\n    return 0;\n}\n\nstatic void opt_input_file(void *optctx, const char *filename)\n{\n    if (input_filename) {\n        av_log(NULL, AV_LOG_FATAL,\n               \"Argument '%s' provided as input filename, but '%s' was already specified.\\n\",\n                filename, input_filename);\n        exit(1);\n    }\n    if (!strcmp(filename, \"-\"))\n        filename = \"pipe:\";\n    input_filename = filename;\n}\n\nstatic int opt_codec(void *optctx, const char *opt, const char *arg)\n{\n   const char *spec = strchr(opt, ':');\n   if (!spec) {\n       av_log(NULL, AV_LOG_ERROR,\n              \"No media specifier was specified in '%s' in option '%s'\\n\",\n               arg, opt);\n       return AVERROR(EINVAL);\n   }\n   spec++;\n   switch (spec[0]) {\n   case 'a' :    audio_codec_name = arg; break;\n   case 's' : subtitle_codec_name = arg; break;\n   case 'v' :    video_codec_name = arg; break;\n   default:\n       av_log(NULL, AV_LOG_ERROR,\n              \"Invalid media specifier '%s' in option '%s'\\n\", spec, opt);\n       return AVERROR(EINVAL);\n   }\n   return 0;\n}\n\nstatic int dummy;\n\nstatic const OptionDef options[] = {\n    CMDUTILS_COMMON_OPTIONS\n    { \"x\", HAS_ARG, { .func_arg = opt_width }, \"force displayed width\", \"width\" },\n    { \"y\", HAS_ARG, { .func_arg = opt_height }, \"force displayed height\", \"height\" },\n    { \"fs\", OPT_BOOL, { &is_full_screen }, \"force full screen\" },\n    { \"an\", OPT_BOOL, { &audio_disable }, \"disable audio\" },\n    { \"vn\", OPT_BOOL, { &video_disable }, \"disable video\" },\n    { \"sn\", OPT_BOOL, { &subtitle_disable }, \"disable subtitling\" },\n    { \"ast\", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, \"select desired audio stream\", \"stream_specifier\" },\n    { \"vst\", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, \"select desired video stream\", \"stream_specifier\" },\n    { \"sst\", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, \"select desired subtitle stream\", \"stream_specifier\" },\n    { \"ss\", HAS_ARG, { .func_arg = opt_seek }, \"seek to a given position in seconds\", \"pos\" },\n    { \"t\", HAS_ARG, { .func_arg = opt_duration }, \"play  \\\"duration\\\" seconds of audio/video\", \"duration\" },\n    { \"bytes\", OPT_INT | HAS_ARG, { &seek_by_bytes }, \"seek by bytes 0=off 1=on -1=auto\", \"val\" },\n    { \"seek_interval\", OPT_FLOAT | HAS_ARG, { &seek_interval }, \"set seek interval for left/right keys, in seconds\", \"seconds\" },\n    { \"nodisp\", OPT_BOOL, { &display_disable }, \"disable graphical display\" },\n    { \"noborder\", OPT_BOOL, { &borderless }, \"borderless window\" },\n    { \"alwaysontop\", OPT_BOOL, { &alwaysontop }, \"window always on top\" },\n    { \"volume\", OPT_INT | HAS_ARG, { &startup_volume}, \"set startup volume 0=min 100=max\", \"volume\" },\n    { \"f\", HAS_ARG, { .func_arg = opt_format }, \"force format\", \"fmt\" },\n    { \"stats\", OPT_BOOL | OPT_EXPERT, { &show_status }, \"show status\", \"\" },\n    { \"fast\", OPT_BOOL | OPT_EXPERT, { &fast }, \"non spec compliant optimizations\", \"\" },\n    { \"genpts\", OPT_BOOL | OPT_EXPERT, { &genpts }, \"generate pts\", \"\" },\n    { \"drp\", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, \"let decoder reorder pts 0=off 1=on -1=auto\", \"\"},\n    { \"lowres\", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, \"\", \"\" },\n    { \"sync\", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, \"set audio-video sync. type (type=audio/video/ext)\", \"type\" },\n    { \"autoexit\", OPT_BOOL | OPT_EXPERT, { &autoexit }, \"exit at the end\", \"\" },\n    { \"exitonkeydown\", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, \"exit on key down\", \"\" },\n    { \"exitonmousedown\", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, \"exit on mouse down\", \"\" },\n    { \"loop\", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, \"set number of times the playback shall be looped\", \"loop count\" },\n    { \"framedrop\", OPT_BOOL | OPT_EXPERT, { &framedrop }, \"drop frames when cpu is too slow\", \"\" },\n    { \"infbuf\", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, \"don't limit the input buffer size (useful with realtime streams)\", \"\" },\n    { \"window_title\", OPT_STRING | HAS_ARG, { &window_title }, \"set window title\", \"window title\" },\n    { \"left\", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_left }, \"set the x position for the left of the window\", \"x pos\" },\n    { \"top\", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_top }, \"set the y position for the top of the window\", \"y pos\" },\n#if CONFIG_AVFILTER\n    { \"vf\", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, \"set video filters\", \"filter_graph\" },\n    { \"af\", OPT_STRING | HAS_ARG, { &afilters }, \"set audio filters\", \"filter_graph\" },\n#endif\n    { \"rdftspeed\", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, \"rdft speed\", \"msecs\" },\n    { \"showmode\", HAS_ARG, { .func_arg = opt_show_mode}, \"select show mode (0 = video, 1 = waves, 2 = RDFT)\", \"mode\" },\n    { \"i\", OPT_BOOL, { &dummy}, \"read specified file\", \"input_file\"},\n    { \"codec\", HAS_ARG, { .func_arg = opt_codec}, \"force decoder\", \"decoder_name\" },\n    { \"acodec\", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &audio_codec_name }, \"force audio decoder\",    \"decoder_name\" },\n    { \"scodec\", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, \"force subtitle decoder\", \"decoder_name\" },\n    { \"vcodec\", HAS_ARG | OPT_STRING | OPT_EXPERT, {    &video_codec_name }, \"force video decoder\",    \"decoder_name\" },\n    { \"autorotate\", OPT_BOOL, { &autorotate }, \"automatically rotate video\", \"\" },\n    { \"find_stream_info\", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info },\n        \"read and decode the streams to fill missing information with heuristics\" },\n    { \"filter_threads\", HAS_ARG | OPT_INT | OPT_EXPERT, { &filter_nbthreads }, \"number of filter threads per graph\" },\n    { NULL, },\n};\n\nstatic void show_usage(void)\n{\n    av_log(NULL, AV_LOG_INFO, \"Simple media player\\n\");\n    av_log(NULL, AV_LOG_INFO, \"usage: %s [options] input_file\\n\", program_name);\n    av_log(NULL, AV_LOG_INFO, \"\\n\");\n}\n\nvoid show_help_default(const char *opt, const char *arg)\n{\n    av_log_set_callback(log_callback_help);\n    show_usage();\n    show_help_options(options, \"Main options:\", 0, OPT_EXPERT, 0);\n    show_help_options(options, \"Advanced options:\", OPT_EXPERT, 0, 0);\n    printf(\"\\n\");\n    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);\n    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);\n#if !CONFIG_AVFILTER\n    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);\n#else\n    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);\n#endif\n    printf(\"\\nWhile playing:\\n\"\n           \"q, ESC              quit\\n\"\n           \"f                   toggle full screen\\n\"\n           \"p, SPC              pause\\n\"\n           \"m                   toggle mute\\n\"\n           \"9, 0                decrease and increase volume respectively\\n\"\n           \"/, *                decrease and increase volume respectively\\n\"\n           \"a                   cycle audio channel in the current program\\n\"\n           \"v                   cycle video channel\\n\"\n           \"t                   cycle subtitle channel in the current program\\n\"\n           \"c                   cycle program\\n\"\n           \"w                   cycle video filters or show modes\\n\"\n           \"s                   activate frame-step mode\\n\"\n           \"left/right          seek backward/forward 10 seconds or to custom interval if -seek_interval is set\\n\"\n           \"down/up             seek backward/forward 1 minute\\n\"\n           \"page down/page up   seek backward/forward 10 minutes\\n\"\n           \"right mouse click   seek to percentage in file corresponding to fraction of width\\n\"\n           \"left double-click   toggle full screen\\n\"\n           );\n}\n\n/* Called from the main */\nint ffplay(int argc, char **argv)\n{\n    int flags;\n    VideoState *is;\n\n    init_dynload();\n\n    av_log_set_flags(AV_LOG_SKIP_REPEATED);\n    parse_loglevel(argc, argv, options);\n\n    /* register all codecs, demux and protocols */\n#if CONFIG_AVDEVICE\n    avdevice_register_all();\n#endif\n    avformat_network_init();\n\n    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).    */\n    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */\n\n    show_banner(argc, argv, options);\n\n    parse_options(NULL, argc, argv, options, opt_input_file);\n\n    if (!input_filename) {\n        show_usage();\n        av_log(NULL, AV_LOG_FATAL, \"An input file must be specified\\n\");\n        av_log(NULL, AV_LOG_FATAL,\n               \"Use -h to get full help or, even better, run 'man %s'\\n\", program_name);\n        exit(1);\n    }\n\n    if (display_disable) {\n        video_disable = 1;\n    }\n    flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;\n    if (audio_disable)\n        flags &= ~SDL_INIT_AUDIO;\n    else {\n        /* Try to work around an occasional ALSA buffer underflow issue when the\n         * period size is NPOT due to ALSA resampling by forcing the buffer size. */\n        if (!SDL_getenv(\"SDL_AUDIO_ALSA_SET_BUFFER_SIZE\"))\n            SDL_setenv(\"SDL_AUDIO_ALSA_SET_BUFFER_SIZE\",\"1\", 1);\n    }\n    if (display_disable)\n        flags &= ~SDL_INIT_VIDEO;\n    if (SDL_Init (flags)) {\n        av_log(NULL, AV_LOG_FATAL, \"Could not initialize SDL - %s\\n\", SDL_GetError());\n        av_log(NULL, AV_LOG_FATAL, \"(Did you set the DISPLAY variable?)\\n\");\n        exit(1);\n    }\n\n    SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);\n    SDL_EventState(SDL_USEREVENT, SDL_IGNORE);\n\n    if (!display_disable) {\n        int flags = SDL_WINDOW_HIDDEN;\n        if (alwaysontop)\n#if SDL_VERSION_ATLEAST(2,0,5)\n            flags |= SDL_WINDOW_ALWAYS_ON_TOP;\n#else\n            av_log(NULL, AV_LOG_WARNING, \"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\\n\");\n#endif\n        if (borderless)\n            flags |= SDL_WINDOW_BORDERLESS;\n        else\n            flags |= SDL_WINDOW_RESIZABLE;\n\n#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR\n        SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, \"0\");\n#endif\n        window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags);\n        SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, \"linear\");\n        if (window) {\n            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);\n            if (!renderer) {\n                av_log(NULL, AV_LOG_WARNING, \"Failed to initialize a hardware accelerated renderer: %s\\n\", SDL_GetError());\n                renderer = SDL_CreateRenderer(window, -1, 0);\n            }\n            if (renderer) {\n                if (!SDL_GetRendererInfo(renderer, &renderer_info))\n                    av_log(NULL, AV_LOG_VERBOSE, \"Initialized %s renderer.\\n\", renderer_info.name);\n            }\n        }\n        if (!window || !renderer || !renderer_info.num_texture_formats) {\n            av_log(NULL, AV_LOG_FATAL, \"Failed to create window or renderer: %s\", SDL_GetError());\n            do_exit(NULL);\n        }\n    }\n\n    is = stream_open(input_filename, file_iformat);\n    if (!is) {\n        av_log(NULL, AV_LOG_FATAL, \"Failed to initialize VideoState!\\n\");\n        do_exit(NULL);\n    }\n\n    event_loop(is);\n\n    /* never returns */\n\n    return 0;\n}\n"
  },
  {
    "path": "src/fftools/ffprobe.c",
    "content": "/*\n * Copyright (c) 2007-2010 Stefano Sabatini\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * simple media prober based on the FFmpeg libraries\n */\n\n#include \"config.h\"\n#include \"libavutil/ffversion.h\"\n\n#include <string.h>\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/version.h\"\n#include \"libavcodec/avcodec.h\"\n#include \"libavcodec/version.h\"\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/display.h\"\n#include \"libavutil/hash.h\"\n#include \"libavutil/hdr_dynamic_metadata.h\"\n#include \"libavutil/mastering_display_metadata.h\"\n#include \"libavutil/hdr_dynamic_vivid_metadata.h\"\n#include \"libavutil/dovi_meta.h\"\n#include \"libavutil/opt.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/spherical.h\"\n#include \"libavutil/stereo3d.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/intreadwrite.h\"\n#include \"libavutil/libm.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/timecode.h\"\n#include \"libavutil/timestamp.h\"\n#include \"libavdevice/avdevice.h\"\n#include \"libavdevice/version.h\"\n#include \"libswscale/swscale.h\"\n#include \"libswscale/version.h\"\n#include \"libswresample/swresample.h\"\n#include \"libswresample/version.h\"\n#include \"libpostproc/postprocess.h\"\n#include \"libpostproc/version.h\"\n#include \"libavfilter/version.h\"\n#include \"cmdutils.h\"\n#include \"opt_common.h\"\n\n#include \"libavutil/thread.h\"\n\n#if !HAVE_THREADS\n#  ifdef pthread_mutex_lock\n#    undef pthread_mutex_lock\n#  endif\n#  define pthread_mutex_lock(a) do{}while(0)\n#  ifdef pthread_mutex_unlock\n#    undef pthread_mutex_unlock\n#  endif\n#  define pthread_mutex_unlock(a) do{}while(0)\n#endif\n\ntypedef struct InputStream {\n    AVStream *st;\n\n    AVCodecContext *dec_ctx;\n} InputStream;\n\ntypedef struct InputFile {\n    AVFormatContext *fmt_ctx;\n\n    InputStream *streams;\n    int       nb_streams;\n} InputFile;\n\nconst char program_name_ffprobe[] = \"ffprobe\";\nconst int program_birth_year_ffprobe = 2007;\n\nstatic int do_bitexact = 0;\nstatic int do_count_frames = 0;\nstatic int do_count_packets = 0;\nstatic int do_read_frames  = 0;\nstatic int do_read_packets = 0;\nstatic int do_show_chapters = 0;\nstatic int do_show_error   = 0;\nstatic int do_show_format  = 0;\nstatic int do_show_frames  = 0;\nstatic int do_show_packets = 0;\nstatic int do_show_programs = 0;\nstatic int do_show_streams = 0;\nstatic int do_show_stream_disposition = 0;\nstatic int do_show_data    = 0;\nstatic int do_show_program_version  = 0;\nstatic int do_show_library_versions = 0;\nstatic int do_show_pixel_formats = 0;\nstatic int do_show_pixel_format_flags = 0;\nstatic int do_show_pixel_format_components = 0;\nstatic int do_show_log = 0;\n\nstatic int do_show_chapter_tags = 0;\nstatic int do_show_format_tags = 0;\nstatic int do_show_frame_tags = 0;\nstatic int do_show_program_tags = 0;\nstatic int do_show_stream_tags = 0;\nstatic int do_show_packet_tags = 0;\n\nstatic int show_value_unit              = 0;\nstatic int use_value_prefix             = 0;\nstatic int use_byte_value_binary_prefix = 0;\nstatic int use_value_sexagesimal_format = 0;\nstatic int show_private_data            = 1;\n\n#define SHOW_OPTIONAL_FIELDS_AUTO       -1\n#define SHOW_OPTIONAL_FIELDS_NEVER       0\n#define SHOW_OPTIONAL_FIELDS_ALWAYS      1\nstatic int show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;\n\nstatic char *print_format;\nstatic char *stream_specifier;\nstatic char *show_data_hash;\n\ntypedef struct ReadInterval {\n    int id;             ///< identifier\n    int64_t start, end; ///< start, end in second/AV_TIME_BASE units\n    int has_start, has_end;\n    int start_is_offset, end_is_offset;\n    int duration_frames;\n} ReadInterval;\n\nstatic ReadInterval *read_intervals;\nstatic int read_intervals_nb = 0;\n\nstatic int find_stream_info  = 1;\n\n/* section structure definition */\n\n#define SECTION_MAX_NB_CHILDREN 10\n\nstruct section {\n    int id;             ///< unique id identifying a section\n    const char *name;\n\n#define SECTION_FLAG_IS_WRAPPER      1 ///< the section only contains other sections, but has no data at its own level\n#define SECTION_FLAG_IS_ARRAY        2 ///< the section contains an array of elements of the same type\n#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.\n                                           ///  For these sections the element_name field is mandatory.\n    int flags;\n    int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1\n    const char *element_name; ///< name of the contained element, if provided\n    const char *unique_name;  ///< unique section name, in case the name is ambiguous\n    AVDictionary *entries_to_show;\n    int show_all_entries;\n};\n\ntypedef enum {\n    SECTION_ID_NONE = -1,\n    SECTION_ID_CHAPTER,\n    SECTION_ID_CHAPTER_TAGS,\n    SECTION_ID_CHAPTERS,\n    SECTION_ID_ERROR,\n    SECTION_ID_FORMAT,\n    SECTION_ID_FORMAT_TAGS,\n    SECTION_ID_FRAME,\n    SECTION_ID_FRAMES,\n    SECTION_ID_FRAME_TAGS,\n    SECTION_ID_FRAME_SIDE_DATA_LIST,\n    SECTION_ID_FRAME_SIDE_DATA,\n    SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST,\n    SECTION_ID_FRAME_SIDE_DATA_TIMECODE,\n    SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST,\n    SECTION_ID_FRAME_SIDE_DATA_COMPONENT,\n    SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST,\n    SECTION_ID_FRAME_SIDE_DATA_PIECE,\n    SECTION_ID_FRAME_LOG,\n    SECTION_ID_FRAME_LOGS,\n    SECTION_ID_LIBRARY_VERSION,\n    SECTION_ID_LIBRARY_VERSIONS,\n    SECTION_ID_PACKET,\n    SECTION_ID_PACKET_TAGS,\n    SECTION_ID_PACKETS,\n    SECTION_ID_PACKETS_AND_FRAMES,\n    SECTION_ID_PACKET_SIDE_DATA_LIST,\n    SECTION_ID_PACKET_SIDE_DATA,\n    SECTION_ID_PIXEL_FORMAT,\n    SECTION_ID_PIXEL_FORMAT_FLAGS,\n    SECTION_ID_PIXEL_FORMAT_COMPONENT,\n    SECTION_ID_PIXEL_FORMAT_COMPONENTS,\n    SECTION_ID_PIXEL_FORMATS,\n    SECTION_ID_PROGRAM_STREAM_DISPOSITION,\n    SECTION_ID_PROGRAM_STREAM_TAGS,\n    SECTION_ID_PROGRAM,\n    SECTION_ID_PROGRAM_STREAMS,\n    SECTION_ID_PROGRAM_STREAM,\n    SECTION_ID_PROGRAM_TAGS,\n    SECTION_ID_PROGRAM_VERSION,\n    SECTION_ID_PROGRAMS,\n    SECTION_ID_ROOT,\n    SECTION_ID_STREAM,\n    SECTION_ID_STREAM_DISPOSITION,\n    SECTION_ID_STREAMS,\n    SECTION_ID_STREAM_TAGS,\n    SECTION_ID_STREAM_SIDE_DATA_LIST,\n    SECTION_ID_STREAM_SIDE_DATA,\n    SECTION_ID_SUBTITLE,\n} SectionID;\n\nstatic struct section sections[] = {\n    [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, \"chapters\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },\n    [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, \"chapter\", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },\n    [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"chapter_tags\" },\n    [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, \"error\", 0, { -1 } },\n    [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, \"format\", 0, { SECTION_ID_FORMAT_TAGS, -1 } },\n    [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"format_tags\" },\n    [SECTION_ID_FRAMES] =             { SECTION_ID_FRAMES, \"frames\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } },\n    [SECTION_ID_FRAME] =              { SECTION_ID_FRAME, \"frame\", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } },\n    [SECTION_ID_FRAME_TAGS] =         { SECTION_ID_FRAME_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"frame_tags\" },\n    [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, \"side_data_list\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = \"side_data\", .unique_name = \"frame_side_data_list\" },\n    [SECTION_ID_FRAME_SIDE_DATA] =     { SECTION_ID_FRAME_SIDE_DATA, \"side_data\", 0, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, -1 }, .unique_name = \"frame_side_data\" },\n    [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] =  { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, \"timecodes\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } },\n    [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] =       { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, \"timecode\", 0, { -1 } },\n    [SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST] = { SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST, \"components\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, -1 } },\n    [SECTION_ID_FRAME_SIDE_DATA_COMPONENT] =      { SECTION_ID_FRAME_SIDE_DATA_COMPONENT, \"component\", 0, { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, -1 } },\n    [SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST] =   { SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST, \"pieces\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_PIECE, -1 } },\n    [SECTION_ID_FRAME_SIDE_DATA_PIECE] =        { SECTION_ID_FRAME_SIDE_DATA_PIECE, \"section\", 0, { -1 } },\n    [SECTION_ID_FRAME_LOGS] =         { SECTION_ID_FRAME_LOGS, \"logs\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } },\n    [SECTION_ID_FRAME_LOG] =          { SECTION_ID_FRAME_LOG, \"log\", 0, { -1 },  },\n    [SECTION_ID_LIBRARY_VERSIONS] =   { SECTION_ID_LIBRARY_VERSIONS, \"library_versions\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },\n    [SECTION_ID_LIBRARY_VERSION] =    { SECTION_ID_LIBRARY_VERSION, \"library_version\", 0, { -1 } },\n    [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, \"packets\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },\n    [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, \"packets_and_frames\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },\n    [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, \"packet\", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },\n    [SECTION_ID_PACKET_TAGS] =        { SECTION_ID_PACKET_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"packet_tags\" },\n    [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, \"side_data_list\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = \"side_data\", .unique_name = \"packet_side_data_list\" },\n    [SECTION_ID_PACKET_SIDE_DATA] =     { SECTION_ID_PACKET_SIDE_DATA, \"side_data\", 0, { -1 }, .unique_name = \"packet_side_data\" },\n    [SECTION_ID_PIXEL_FORMATS] =      { SECTION_ID_PIXEL_FORMATS, \"pixel_formats\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },\n    [SECTION_ID_PIXEL_FORMAT] =       { SECTION_ID_PIXEL_FORMAT, \"pixel_format\", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } },\n    [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, \"flags\", 0, { -1 }, .unique_name = \"pixel_format_flags\" },\n    [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, \"components\", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = \"pixel_format_components\" },\n    [SECTION_ID_PIXEL_FORMAT_COMPONENT]  = { SECTION_ID_PIXEL_FORMAT_COMPONENT, \"component\", 0, { -1 } },\n    [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, \"disposition\", 0, { -1 }, .unique_name = \"program_stream_disposition\" },\n    [SECTION_ID_PROGRAM_STREAM_TAGS] =        { SECTION_ID_PROGRAM_STREAM_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"program_stream_tags\" },\n    [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, \"program\", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },\n    [SECTION_ID_PROGRAM_STREAMS] =            { SECTION_ID_PROGRAM_STREAMS, \"streams\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = \"program_streams\" },\n    [SECTION_ID_PROGRAM_STREAM] =             { SECTION_ID_PROGRAM_STREAM, \"stream\", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = \"program_stream\" },\n    [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"program_tags\" },\n    [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, \"program_version\", 0, { -1 } },\n    [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, \"programs\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },\n    [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, \"root\", SECTION_FLAG_IS_WRAPPER,\n                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,\n                                          SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,\n                                          SECTION_ID_PIXEL_FORMATS, -1} },\n    [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, \"streams\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },\n    [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, \"stream\", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } },\n    [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, \"disposition\", 0, { -1 }, .unique_name = \"stream_disposition\" },\n    [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, \"tags\", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = \"tag\", .unique_name = \"stream_tags\" },\n    [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, \"side_data_list\", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = \"side_data\", .unique_name = \"stream_side_data_list\" },\n    [SECTION_ID_STREAM_SIDE_DATA] =     { SECTION_ID_STREAM_SIDE_DATA, \"side_data\", 0, { -1 }, .unique_name = \"stream_side_data\" },\n    [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, \"subtitle\", 0, { -1 } },\n};\n\nstatic const OptionDef *options;\n\n/* FFprobe context */\nstatic const char *input_filename;\nstatic const char *print_input_filename;\nstatic const AVInputFormat *iformat = NULL;\nstatic const char *output_filename = NULL;\n\nstatic struct AVHashContext *hash;\n\nstatic const struct {\n    double bin_val;\n    double dec_val;\n    const char *bin_str;\n    const char *dec_str;\n} si_prefixes[] = {\n    { 1.0, 1.0, \"\", \"\" },\n    { 1.024e3, 1e3, \"Ki\", \"K\" },\n    { 1.048576e6, 1e6, \"Mi\", \"M\" },\n    { 1.073741824e9, 1e9, \"Gi\", \"G\" },\n    { 1.099511627776e12, 1e12, \"Ti\", \"T\" },\n    { 1.125899906842624e15, 1e15, \"Pi\", \"P\" },\n};\n\nstatic const char unit_second_str[]         = \"s\"    ;\nstatic const char unit_hertz_str[]          = \"Hz\"   ;\nstatic const char unit_byte_str[]           = \"byte\" ;\nstatic const char unit_bit_per_second_str[] = \"bit/s\";\n\nstatic int nb_streams;\nstatic uint64_t *nb_streams_packets;\nstatic uint64_t *nb_streams_frames;\nstatic int *selected_streams;\n\n#if HAVE_THREADS\npthread_mutex_t log_mutex;\n#endif\ntypedef struct LogBuffer {\n    char *context_name;\n    int log_level;\n    char *log_message;\n    AVClassCategory category;\n    char *parent_name;\n    AVClassCategory parent_category;\n}LogBuffer;\n\nstatic LogBuffer *log_buffer;\nstatic int log_buffer_size;\n\nstatic void log_callback(void *ptr, int level, const char *fmt, va_list vl)\n{\n    AVClass* avc = ptr ? *(AVClass **) ptr : NULL;\n    va_list vl2;\n    char line[1024];\n    static int print_prefix = 1;\n    void *new_log_buffer;\n\n    va_copy(vl2, vl);\n    av_log_default_callback(ptr, level, fmt, vl);\n    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);\n    va_end(vl2);\n\n#if HAVE_THREADS\n    pthread_mutex_lock(&log_mutex);\n\n    new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer));\n    if (new_log_buffer) {\n        char *msg;\n        int i;\n\n        log_buffer = new_log_buffer;\n        memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size]));\n        log_buffer[log_buffer_size].context_name= avc ? av_strdup(avc->item_name(ptr)) : NULL;\n        if (avc) {\n            if (avc->get_category) log_buffer[log_buffer_size].category = avc->get_category(ptr);\n            else                   log_buffer[log_buffer_size].category = avc->category;\n        }\n        log_buffer[log_buffer_size].log_level   = level;\n        msg = log_buffer[log_buffer_size].log_message = av_strdup(line);\n        for (i=strlen(msg) - 1; i>=0 && msg[i] == '\\n'; i--) {\n            msg[i] = 0;\n        }\n        if (avc && avc->parent_log_context_offset) {\n            AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) +\n                                   avc->parent_log_context_offset);\n            if (parent && *parent) {\n                log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent));\n                log_buffer[log_buffer_size].parent_category =\n                    (*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category;\n            }\n        }\n        log_buffer_size ++;\n    }\n\n    pthread_mutex_unlock(&log_mutex);\n#endif\n}\n\nstatic void ffprobe_cleanup(int ret)\n{\n    int i;\n    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)\n        av_dict_free(&(sections[i].entries_to_show));\n\n#if HAVE_THREADS\n    pthread_mutex_destroy(&log_mutex);\n#endif\n\n    do_bitexact = 0;\n    do_count_frames = 0;\n    do_count_packets = 0;\n    do_read_frames  = 0;\n    do_read_packets = 0;\n    do_show_chapters = 0;\n    do_show_error   = 0;\n    do_show_format  = 0;\n    do_show_frames  = 0;\n    do_show_packets = 0;\n    do_show_programs = 0;\n    do_show_streams = 0;\n    do_show_stream_disposition = 0;\n    do_show_data    = 0;\n    do_show_program_version  = 0;\n    do_show_library_versions = 0;\n    do_show_pixel_formats = 0;\n    do_show_pixel_format_flags = 0;\n    do_show_pixel_format_components = 0;\n    do_show_log = 0;\n    do_show_chapter_tags = 0;\n    do_show_format_tags = 0;\n    do_show_frame_tags = 0;\n    do_show_program_tags = 0;\n    do_show_stream_tags = 0;\n    do_show_packet_tags = 0;\n    show_value_unit              = 0;\n    use_value_prefix             = 0;\n    use_byte_value_binary_prefix = 0;\n    use_value_sexagesimal_format = 0;\n    show_private_data            = 1;\n    show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;\n    print_format = NULL;\n    stream_specifier = NULL;\n    show_data_hash = NULL;\n    read_intervals = NULL;\n    read_intervals_nb = 0;\n    find_stream_info  = 1;\n    input_filename = NULL;\n    print_input_filename = NULL;\n    iformat = NULL;\n    output_filename = NULL;\n    hash = NULL;\n    nb_streams = 0;\n    nb_streams_packets = NULL;\n    nb_streams_frames = NULL;\n    selected_streams = NULL;\n    log_buffer = NULL;\n    log_buffer_size = 0;\n\n    av_log(NULL, AV_LOG_DEBUG, \"FFprobe: Cleanup done.\\n\");\n}\n\nstruct unit_value {\n    union { double d; long long int i; } val;\n    const char *unit;\n};\n\nstatic char *value_string(char *buf, int buf_size, struct unit_value uv)\n{\n    double vald;\n    long long int vali;\n    int show_float = 0;\n\n    if (uv.unit == unit_second_str) {\n        vald = uv.val.d;\n        show_float = 1;\n    } else {\n        vald = vali = uv.val.i;\n    }\n\n    if (uv.unit == unit_second_str && use_value_sexagesimal_format) {\n        double secs;\n        int hours, mins;\n        secs  = vald;\n        mins  = (int)secs / 60;\n        secs  = secs - mins * 60;\n        hours = mins / 60;\n        mins %= 60;\n        snprintf(buf, buf_size, \"%d:%02d:%09.6f\", hours, mins, secs);\n    } else {\n        const char *prefix_string = \"\";\n\n        if (use_value_prefix && vald > 1) {\n            long long int index;\n\n            if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {\n                index = (long long int) (log2(vald)) / 10;\n                index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);\n                vald /= si_prefixes[index].bin_val;\n                prefix_string = si_prefixes[index].bin_str;\n            } else {\n                index = (long long int) (log10(vald)) / 3;\n                index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);\n                vald /= si_prefixes[index].dec_val;\n                prefix_string = si_prefixes[index].dec_str;\n            }\n            vali = vald;\n        }\n\n        if (show_float || (use_value_prefix && vald != (long long int)vald))\n            snprintf(buf, buf_size, \"%f\", vald);\n        else\n            snprintf(buf, buf_size, \"%lld\", vali);\n        av_strlcatf(buf, buf_size, \"%s%s%s\", *prefix_string || show_value_unit ? \" \" : \"\",\n                 prefix_string, show_value_unit ? uv.unit : \"\");\n    }\n\n    return buf;\n}\n\n/* WRITERS API */\n\ntypedef struct WriterContext WriterContext;\n\n#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1\n#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2\n\ntypedef enum {\n    WRITER_STRING_VALIDATION_FAIL,\n    WRITER_STRING_VALIDATION_REPLACE,\n    WRITER_STRING_VALIDATION_IGNORE,\n    WRITER_STRING_VALIDATION_NB\n} StringValidation;\n\ntypedef struct Writer {\n    const AVClass *priv_class;      ///< private class of the writer, if any\n    int priv_size;                  ///< private size for the writer context\n    const char *name;\n\n    int  (*init)  (WriterContext *wctx);\n    void (*uninit)(WriterContext *wctx);\n\n    void (*print_section_header)(WriterContext *wctx);\n    void (*print_section_footer)(WriterContext *wctx);\n    void (*print_integer)       (WriterContext *wctx, const char *, long long int);\n    void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);\n    void (*print_string)        (WriterContext *wctx, const char *, const char *);\n    int flags;                  ///< a combination or WRITER_FLAG_*\n} Writer;\n\n#define SECTION_MAX_NB_LEVELS 10\n\nstruct WriterContext {\n    const AVClass *class;           ///< class of the writer\n    const Writer *writer;           ///< the Writer of which this is an instance\n    AVIOContext *avio;              ///< the I/O context used to write\n\n    void (* writer_w8)(WriterContext *wctx, int b);\n    void (* writer_put_str)(WriterContext *wctx, const char *str);\n    void (* writer_printf)(WriterContext *wctx, const char *fmt, ...);\n\n    char *name;                     ///< name of this writer instance\n    void *priv;                     ///< private data for use by the filter\n\n    const struct section *sections; ///< array containing all sections\n    int nb_sections;                ///< number of sections\n\n    int level;                      ///< current level, starting from 0\n\n    /** number of the item printed in the given section, starting from 0 */\n    unsigned int nb_item[SECTION_MAX_NB_LEVELS];\n\n    /** section per each level */\n    const struct section *section[SECTION_MAX_NB_LEVELS];\n    AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,\n                                                  ///  used by various writers\n\n    unsigned int nb_section_packet; ///< number of the packet section in case we are in \"packets_and_frames\" section\n    unsigned int nb_section_frame;  ///< number of the frame  section in case we are in \"packets_and_frames\" section\n    unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames\n\n    int string_validation;\n    char *string_validation_replacement;\n    unsigned int string_validation_utf8_flags;\n};\n\nstatic const char *writer_get_name(void *p)\n{\n    WriterContext *wctx = p;\n    return wctx->writer->name;\n}\n\n#define OFFSET(x) offsetof(WriterContext, x)\n\nstatic const AVOption writer_options[] = {\n    { \"string_validation\", \"set string validation mode\",\n      OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = \"sv\" },\n    { \"sv\", \"set string validation mode\",\n      OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = \"sv\" },\n    { \"ignore\",  NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE},  .unit = \"sv\" },\n    { \"replace\", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = \"sv\" },\n    { \"fail\",    NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL},    .unit = \"sv\" },\n    { \"string_validation_replacement\", \"set string validation replacement string\", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=\"\"}},\n    { \"svr\", \"set string validation replacement string\", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=\"\\xEF\\xBF\\xBD\"}},\n    { NULL }\n};\n\nstatic void *writer_child_next(void *obj, void *prev)\n{\n    WriterContext *ctx = obj;\n    if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)\n        return ctx->priv;\n    return NULL;\n}\n\nstatic const AVClass writer_class = {\n    .class_name = \"Writer\",\n    .item_name  = writer_get_name,\n    .option     = writer_options,\n    .version    = LIBAVUTIL_VERSION_INT,\n    .child_next = writer_child_next,\n};\n\nstatic int writer_close(WriterContext **wctx)\n{\n    int i;\n    int ret = 0;\n\n    if (!*wctx)\n        return -1;\n\n    if ((*wctx)->writer->uninit)\n        (*wctx)->writer->uninit(*wctx);\n    for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)\n        av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);\n    if ((*wctx)->writer->priv_class)\n        av_opt_free((*wctx)->priv);\n    av_freep(&((*wctx)->priv));\n    av_opt_free(*wctx);\n    if ((*wctx)->avio) {\n        avio_flush((*wctx)->avio);\n        ret = avio_close((*wctx)->avio);\n    }\n    av_freep(wctx);\n    return ret;\n}\n\nstatic void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)\n{\n    int i;\n    av_bprintf(bp, \"0X\");\n    for (i = 0; i < ubuf_size; i++)\n        av_bprintf(bp, \"%02X\", ubuf[i]);\n}\n\nstatic inline void writer_w8_avio(WriterContext *wctx, int b)\n{\n    avio_w8(wctx->avio, b);\n}\n\nstatic inline void writer_put_str_avio(WriterContext *wctx, const char *str)\n{\n    avio_write(wctx->avio, str, strlen(str));\n}\n\nstatic inline void writer_printf_avio(WriterContext *wctx, const char *fmt, ...)\n{\n    va_list ap;\n\n    va_start(ap, fmt);\n    avio_vprintf(wctx->avio, fmt, ap);\n    va_end(ap);\n}\n\nstatic inline void writer_w8_printf(WriterContext *wctx, int b)\n{\n    printf(\"%c\", b);\n}\n\nstatic inline void writer_put_str_printf(WriterContext *wctx, const char *str)\n{\n    printf(\"%s\", str);\n}\n\nstatic inline void writer_printf_printf(WriterContext *wctx, const char *fmt, ...)\n{\n    va_list ap;\n\n    va_start(ap, fmt);\n    vprintf(fmt, ap);\n    va_end(ap);\n}\n\nstatic int writer_open(WriterContext **wctx, const Writer *writer, const char *args,\n                       const struct section *sections, int nb_sections, const char *output)\n{\n    int i, ret = 0;\n\n    if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {\n        ret = AVERROR(ENOMEM);\n        goto fail;\n    }\n\n    (*wctx)->class = &writer_class;\n    (*wctx)->writer = writer;\n    (*wctx)->level = -1;\n    (*wctx)->sections = sections;\n    (*wctx)->nb_sections = nb_sections;\n\n    av_opt_set_defaults(*wctx);\n\n    if (writer->priv_class) {\n        void *priv_ctx = (*wctx)->priv;\n        *((const AVClass **)priv_ctx) = writer->priv_class;\n        av_opt_set_defaults(priv_ctx);\n    }\n\n    /* convert options to dictionary */\n    if (args) {\n        AVDictionary *opts = NULL;\n        const AVDictionaryEntry *opt = NULL;\n\n        if ((ret = av_dict_parse_string(&opts, args, \"=\", \":\", 0)) < 0) {\n            av_log(*wctx, AV_LOG_ERROR, \"Failed to parse option string '%s' provided to writer context\\n\", args);\n            av_dict_free(&opts);\n            goto fail;\n        }\n\n        while ((opt = av_dict_get(opts, \"\", opt, AV_DICT_IGNORE_SUFFIX))) {\n            if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {\n                av_log(*wctx, AV_LOG_ERROR, \"Failed to set option '%s' with value '%s' provided to writer context\\n\",\n                       opt->key, opt->value);\n                av_dict_free(&opts);\n                goto fail;\n            }\n        }\n\n        av_dict_free(&opts);\n    }\n\n    /* validate replace string */\n    {\n        const uint8_t *p = (*wctx)->string_validation_replacement;\n        const uint8_t *endp = p + strlen(p);\n        while (*p) {\n            const uint8_t *p0 = p;\n            int32_t code;\n            ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);\n            if (ret < 0) {\n                AVBPrint bp;\n                av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);\n                bprint_bytes(&bp, p0, p-p0),\n                    av_log(wctx, AV_LOG_ERROR,\n                           \"Invalid UTF8 sequence %s found in string validation replace '%s'\\n\",\n                           bp.str, (*wctx)->string_validation_replacement);\n                return ret;\n            }\n        }\n    }\n\n    if (!output_filename) {\n        (*wctx)->writer_w8 = writer_w8_printf;\n        (*wctx)->writer_put_str = writer_put_str_printf;\n        (*wctx)->writer_printf = writer_printf_printf;\n    } else {\n        if ((ret = avio_open(&(*wctx)->avio, output, AVIO_FLAG_WRITE)) < 0) {\n            av_log(*wctx, AV_LOG_ERROR,\n                   \"Failed to open output '%s' with error: %s\\n\", output, av_err2str(ret));\n            goto fail;\n        }\n        (*wctx)->writer_w8 = writer_w8_avio;\n        (*wctx)->writer_put_str = writer_put_str_avio;\n        (*wctx)->writer_printf = writer_printf_avio;\n    }\n\n    for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)\n        av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    if ((*wctx)->writer->init)\n        ret = (*wctx)->writer->init(*wctx);\n    if (ret < 0)\n        goto fail;\n\n    return 0;\n\nfail:\n    writer_close(wctx);\n    return ret;\n}\n\nstatic inline void writer_print_section_header(WriterContext *wctx,\n                                               int section_id)\n{\n    int parent_section_id;\n    wctx->level++;\n    av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);\n    parent_section_id = wctx->level ?\n        (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;\n\n    wctx->nb_item[wctx->level] = 0;\n    wctx->section[wctx->level] = &wctx->sections[section_id];\n\n    if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {\n        wctx->nb_section_packet = wctx->nb_section_frame =\n        wctx->nb_section_packet_frame = 0;\n    } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {\n        wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?\n            wctx->nb_section_packet : wctx->nb_section_frame;\n    }\n\n    if (wctx->writer->print_section_header)\n        wctx->writer->print_section_header(wctx);\n}\n\nstatic inline void writer_print_section_footer(WriterContext *wctx)\n{\n    int section_id = wctx->section[wctx->level]->id;\n    int parent_section_id = wctx->level ?\n        wctx->section[wctx->level-1]->id : SECTION_ID_NONE;\n\n    if (parent_section_id != SECTION_ID_NONE)\n        wctx->nb_item[wctx->level-1]++;\n    if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {\n        if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;\n        else                                     wctx->nb_section_frame++;\n    }\n    if (wctx->writer->print_section_footer)\n        wctx->writer->print_section_footer(wctx);\n    wctx->level--;\n}\n\nstatic inline void writer_print_integer(WriterContext *wctx,\n                                        const char *key, long long int val)\n{\n    const struct section *section = wctx->section[wctx->level];\n\n    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {\n        wctx->writer->print_integer(wctx, key, val);\n        wctx->nb_item[wctx->level]++;\n    }\n}\n\nstatic inline int validate_string(WriterContext *wctx, char **dstp, const char *src)\n{\n    const uint8_t *p, *endp;\n    AVBPrint dstbuf;\n    int invalid_chars_nb = 0, ret = 0;\n\n    av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);\n\n    endp = src + strlen(src);\n    for (p = (uint8_t *)src; *p;) {\n        uint32_t code;\n        int invalid = 0;\n        const uint8_t *p0 = p;\n\n        if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {\n            AVBPrint bp;\n            av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);\n            bprint_bytes(&bp, p0, p-p0);\n            av_log(wctx, AV_LOG_DEBUG,\n                   \"Invalid UTF-8 sequence %s found in string '%s'\\n\", bp.str, src);\n            invalid = 1;\n        }\n\n        if (invalid) {\n            invalid_chars_nb++;\n\n            switch (wctx->string_validation) {\n            case WRITER_STRING_VALIDATION_FAIL:\n                av_log(wctx, AV_LOG_ERROR,\n                       \"Invalid UTF-8 sequence found in string '%s'\\n\", src);\n                ret = AVERROR_INVALIDDATA;\n                goto end;\n                break;\n\n            case WRITER_STRING_VALIDATION_REPLACE:\n                av_bprintf(&dstbuf, \"%s\", wctx->string_validation_replacement);\n                break;\n            }\n        }\n\n        if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)\n            av_bprint_append_data(&dstbuf, p0, p-p0);\n    }\n\n    if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {\n        av_log(wctx, AV_LOG_WARNING,\n               \"%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\\n\",\n               invalid_chars_nb, src, wctx->string_validation_replacement);\n    }\n\nend:\n    av_bprint_finalize(&dstbuf, dstp);\n    return ret;\n}\n\n#define PRINT_STRING_OPT      1\n#define PRINT_STRING_VALIDATE 2\n\nstatic inline int writer_print_string(WriterContext *wctx,\n                                      const char *key, const char *val, int flags)\n{\n    const struct section *section = wctx->section[wctx->level];\n    int ret = 0;\n\n    if (show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER ||\n        (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO\n        && (flags & PRINT_STRING_OPT)\n        && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS)))\n        return 0;\n\n    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {\n        if (flags & PRINT_STRING_VALIDATE) {\n            char *key1 = NULL, *val1 = NULL;\n            ret = validate_string(wctx, &key1, key);\n            if (ret < 0) goto end;\n            ret = validate_string(wctx, &val1, val);\n            if (ret < 0) goto end;\n            wctx->writer->print_string(wctx, key1, val1);\n        end:\n            if (ret < 0) {\n                av_log(wctx, AV_LOG_ERROR,\n                       \"Invalid key=value string combination %s=%s in section %s\\n\",\n                       key, val, section->unique_name);\n            }\n            av_free(key1);\n            av_free(val1);\n        } else {\n            wctx->writer->print_string(wctx, key, val);\n        }\n\n        wctx->nb_item[wctx->level]++;\n    }\n\n    return ret;\n}\n\nstatic inline void writer_print_rational(WriterContext *wctx,\n                                         const char *key, AVRational q, char sep)\n{\n    AVBPrint buf;\n    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    av_bprintf(&buf, \"%d%c%d\", q.num, sep, q.den);\n    writer_print_string(wctx, key, buf.str, 0);\n}\n\nstatic void writer_print_time(WriterContext *wctx, const char *key,\n                              int64_t ts, const AVRational *time_base, int is_duration)\n{\n    char buf[128];\n\n    if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {\n        writer_print_string(wctx, key, \"N/A\", PRINT_STRING_OPT);\n    } else {\n        double d = ts * av_q2d(*time_base);\n        struct unit_value uv;\n        uv.val.d = d;\n        uv.unit = unit_second_str;\n        value_string(buf, sizeof(buf), uv);\n        writer_print_string(wctx, key, buf, 0);\n    }\n}\n\nstatic void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)\n{\n    if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {\n        writer_print_string(wctx, key, \"N/A\", PRINT_STRING_OPT);\n    } else {\n        writer_print_integer(wctx, key, ts);\n    }\n}\n\nstatic void writer_print_data(WriterContext *wctx, const char *name,\n                              const uint8_t *data, int size)\n{\n    AVBPrint bp;\n    int offset = 0, l, i;\n\n    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);\n    av_bprintf(&bp, \"\\n\");\n    while (size) {\n        av_bprintf(&bp, \"%08x: \", offset);\n        l = FFMIN(size, 16);\n        for (i = 0; i < l; i++) {\n            av_bprintf(&bp, \"%02x\", data[i]);\n            if (i & 1)\n                av_bprintf(&bp, \" \");\n        }\n        av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);\n        for (i = 0; i < l; i++)\n            av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);\n        av_bprintf(&bp, \"\\n\");\n        offset += l;\n        data   += l;\n        size   -= l;\n    }\n    writer_print_string(wctx, name, bp.str, 0);\n    av_bprint_finalize(&bp, NULL);\n}\n\nstatic void writer_print_data_hash(WriterContext *wctx, const char *name,\n                                   const uint8_t *data, int size)\n{\n    char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };\n\n    if (!hash)\n        return;\n    av_hash_init(hash);\n    av_hash_update(hash, data, size);\n    snprintf(buf, sizeof(buf), \"%s:\", av_hash_get_name(hash));\n    p = buf + strlen(buf);\n    av_hash_final_hex(hash, p, buf + sizeof(buf) - p);\n    writer_print_string(wctx, name, buf, 0);\n}\n\nstatic void writer_print_integers(WriterContext *wctx, const char *name,\n                                  uint8_t *data, int size, const char *format,\n                                  int columns, int bytes, int offset_add)\n{\n    AVBPrint bp;\n    int offset = 0, l, i;\n\n    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);\n    av_bprintf(&bp, \"\\n\");\n    while (size) {\n        av_bprintf(&bp, \"%08x: \", offset);\n        l = FFMIN(size, columns);\n        for (i = 0; i < l; i++) {\n            if      (bytes == 1) av_bprintf(&bp, format, *data);\n            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));\n            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));\n            data += bytes;\n            size --;\n        }\n        av_bprintf(&bp, \"\\n\");\n        offset += offset_add;\n    }\n    writer_print_string(wctx, name, bp.str, 0);\n    av_bprint_finalize(&bp, NULL);\n}\n\n#define writer_w8(wctx_, b_) (wctx_)->writer_w8(wctx_, b_)\n#define writer_put_str(wctx_, str_) (wctx_)->writer_put_str(wctx_, str_)\n#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer_printf(wctx_, fmt_, __VA_ARGS__)\n\n#define MAX_REGISTERED_WRITERS_NB 64\n\nstatic const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];\n\nstatic int writer_register(const Writer *writer)\n{\n    static int next_registered_writer_idx = 0;\n\n    if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)\n        return AVERROR(ENOMEM);\n\n    registered_writers[next_registered_writer_idx++] = writer;\n    return 0;\n}\n\nstatic const Writer *writer_get_by_name(const char *name)\n{\n    int i;\n\n    for (i = 0; registered_writers[i]; i++)\n        if (!strcmp(registered_writers[i]->name, name))\n            return registered_writers[i];\n\n    return NULL;\n}\n\n\n/* WRITERS */\n\n#define DEFINE_WRITER_CLASS(name)                   \\\nstatic const char *name##_get_name(void *ctx)       \\\n{                                                   \\\n    return #name ;                                  \\\n}                                                   \\\nstatic const AVClass name##_class = {               \\\n    .class_name = #name,                            \\\n    .item_name  = name##_get_name,                  \\\n    .option     = name##_options                    \\\n}\n\n/* Default output */\n\ntypedef struct DefaultContext {\n    const AVClass *class;\n    int nokey;\n    int noprint_wrappers;\n    int nested_section[SECTION_MAX_NB_LEVELS];\n} DefaultContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(DefaultContext, x)\n\nstatic const AVOption default_options[] = {\n    { \"noprint_wrappers\", \"do not print headers and footers\", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    { \"nw\",               \"do not print headers and footers\", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    { \"nokey\",          \"force no key printing\",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    { \"nk\",             \"force no key printing\",     OFFSET(nokey),          AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(default);\n\n/* lame uppercasing routine, assumes the string is lower case ASCII */\nstatic inline char *upcase_string(char *dst, size_t dst_size, const char *src)\n{\n    int i;\n    for (i = 0; src[i] && i < dst_size-1; i++)\n        dst[i] = av_toupper(src[i]);\n    dst[i] = 0;\n    return dst;\n}\n\nstatic void default_print_section_header(WriterContext *wctx)\n{\n    DefaultContext *def = wctx->priv;\n    char buf[32];\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    av_bprint_clear(&wctx->section_pbuf[wctx->level]);\n    if (parent_section &&\n        !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {\n        def->nested_section[wctx->level] = 1;\n        av_bprintf(&wctx->section_pbuf[wctx->level], \"%s%s:\",\n                   wctx->section_pbuf[wctx->level-1].str,\n                   upcase_string(buf, sizeof(buf),\n                                 av_x_if_null(section->element_name, section->name)));\n    }\n\n    if (def->noprint_wrappers || def->nested_section[wctx->level])\n        return;\n\n    if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))\n        writer_printf(wctx, \"[%s]\\n\", upcase_string(buf, sizeof(buf), section->name));\n}\n\nstatic void default_print_section_footer(WriterContext *wctx)\n{\n    DefaultContext *def = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n    char buf[32];\n\n    if (def->noprint_wrappers || def->nested_section[wctx->level])\n        return;\n\n    if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))\n        writer_printf(wctx, \"[/%s]\\n\", upcase_string(buf, sizeof(buf), section->name));\n}\n\nstatic void default_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    DefaultContext *def = wctx->priv;\n\n    if (!def->nokey)\n        writer_printf(wctx, \"%s%s=\", wctx->section_pbuf[wctx->level].str, key);\n    writer_printf(wctx, \"%s\\n\", value);\n}\n\nstatic void default_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    DefaultContext *def = wctx->priv;\n\n    if (!def->nokey)\n        writer_printf(wctx, \"%s%s=\", wctx->section_pbuf[wctx->level].str, key);\n    writer_printf(wctx, \"%lld\\n\", value);\n}\n\nstatic const Writer default_writer = {\n    .name                  = \"default\",\n    .priv_size             = sizeof(DefaultContext),\n    .print_section_header  = default_print_section_header,\n    .print_section_footer  = default_print_section_footer,\n    .print_integer         = default_print_int,\n    .print_string          = default_print_str,\n    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,\n    .priv_class            = &default_class,\n};\n\n/* Compact output */\n\n/**\n * Apply C-language-like string escaping.\n */\nstatic const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)\n{\n    const char *p;\n\n    for (p = src; *p; p++) {\n        switch (*p) {\n        case '\\b': av_bprintf(dst, \"%s\", \"\\\\b\");  break;\n        case '\\f': av_bprintf(dst, \"%s\", \"\\\\f\");  break;\n        case '\\n': av_bprintf(dst, \"%s\", \"\\\\n\");  break;\n        case '\\r': av_bprintf(dst, \"%s\", \"\\\\r\");  break;\n        case '\\\\': av_bprintf(dst, \"%s\", \"\\\\\\\\\"); break;\n        default:\n            if (*p == sep)\n                av_bprint_chars(dst, '\\\\', 1);\n            av_bprint_chars(dst, *p, 1);\n        }\n    }\n    return dst->str;\n}\n\n/**\n * Quote fields containing special characters, check RFC4180.\n */\nstatic const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)\n{\n    char meta_chars[] = { sep, '\"', '\\n', '\\r', '\\0' };\n    int needs_quoting = !!src[strcspn(src, meta_chars)];\n\n    if (needs_quoting)\n        av_bprint_chars(dst, '\"', 1);\n\n    for (; *src; src++) {\n        if (*src == '\"')\n            av_bprint_chars(dst, '\"', 1);\n        av_bprint_chars(dst, *src, 1);\n    }\n    if (needs_quoting)\n        av_bprint_chars(dst, '\"', 1);\n    return dst->str;\n}\n\nstatic const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)\n{\n    return src;\n}\n\ntypedef struct CompactContext {\n    const AVClass *class;\n    char *item_sep_str;\n    char item_sep;\n    int nokey;\n    int print_section;\n    char *escape_mode_str;\n    const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);\n    int nested_section[SECTION_MAX_NB_LEVELS];\n    int has_nested_elems[SECTION_MAX_NB_LEVELS];\n    int terminate_line[SECTION_MAX_NB_LEVELS];\n} CompactContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(CompactContext, x)\n\nstatic const AVOption compact_options[]= {\n    {\"item_sep\", \"set item separator\",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=\"|\"},  0, 0 },\n    {\"s\",        \"set item separator\",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=\"|\"},  0, 0 },\n    {\"nokey\",    \"force no key printing\", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },\n    {\"nk\",       \"force no key printing\", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=0},    0,        1        },\n    {\"escape\",   \"set escape mode\",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str=\"c\"},  0, 0 },\n    {\"e\",        \"set escape mode\",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str=\"c\"},  0, 0 },\n    {\"print_section\", \"print section name\", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {\"p\",             \"print section name\", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(compact);\n\nstatic av_cold int compact_init(WriterContext *wctx)\n{\n    CompactContext *compact = wctx->priv;\n\n    if (strlen(compact->item_sep_str) != 1) {\n        av_log(wctx, AV_LOG_ERROR, \"Item separator '%s' specified, but must contain a single character\\n\",\n               compact->item_sep_str);\n        return AVERROR(EINVAL);\n    }\n    compact->item_sep = compact->item_sep_str[0];\n\n    if      (!strcmp(compact->escape_mode_str, \"none\")) compact->escape_str = none_escape_str;\n    else if (!strcmp(compact->escape_mode_str, \"c\"   )) compact->escape_str = c_escape_str;\n    else if (!strcmp(compact->escape_mode_str, \"csv\" )) compact->escape_str = csv_escape_str;\n    else {\n        av_log(wctx, AV_LOG_ERROR, \"Unknown escape mode '%s'\\n\", compact->escape_mode_str);\n        return AVERROR(EINVAL);\n    }\n\n    return 0;\n}\n\nstatic void compact_print_section_header(WriterContext *wctx)\n{\n    CompactContext *compact = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n    compact->terminate_line[wctx->level] = 1;\n    compact->has_nested_elems[wctx->level] = 0;\n\n    av_bprint_clear(&wctx->section_pbuf[wctx->level]);\n    if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&\n        !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {\n        compact->nested_section[wctx->level] = 1;\n        compact->has_nested_elems[wctx->level-1] = 1;\n        av_bprintf(&wctx->section_pbuf[wctx->level], \"%s%s:\",\n                   wctx->section_pbuf[wctx->level-1].str,\n                   (char *)av_x_if_null(section->element_name, section->name));\n        wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];\n    } else {\n        if (parent_section && compact->has_nested_elems[wctx->level-1] &&\n            (section->flags & SECTION_FLAG_IS_ARRAY)) {\n            compact->terminate_line[wctx->level-1] = 0;\n        }\n        if (parent_section && !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)) &&\n            wctx->level && wctx->nb_item[wctx->level-1])\n            writer_w8(wctx, compact->item_sep);\n        if (compact->print_section &&\n            !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))\n            writer_printf(wctx, \"%s%c\", section->name, compact->item_sep);\n    }\n}\n\nstatic void compact_print_section_footer(WriterContext *wctx)\n{\n    CompactContext *compact = wctx->priv;\n\n    if (!compact->nested_section[wctx->level] &&\n        compact->terminate_line[wctx->level] &&\n        !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))\n        writer_w8(wctx, '\\n');\n}\n\nstatic void compact_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    CompactContext *compact = wctx->priv;\n    AVBPrint buf;\n\n    if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);\n    if (!compact->nokey)\n        writer_printf(wctx, \"%s%s=\", wctx->section_pbuf[wctx->level].str, key);\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n    writer_put_str(wctx, compact->escape_str(&buf, value, compact->item_sep, wctx));\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic void compact_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    CompactContext *compact = wctx->priv;\n\n    if (wctx->nb_item[wctx->level]) writer_w8(wctx, compact->item_sep);\n    if (!compact->nokey)\n        writer_printf(wctx, \"%s%s=\", wctx->section_pbuf[wctx->level].str, key);\n    writer_printf(wctx, \"%lld\", value);\n}\n\nstatic const Writer compact_writer = {\n    .name                 = \"compact\",\n    .priv_size            = sizeof(CompactContext),\n    .init                 = compact_init,\n    .print_section_header = compact_print_section_header,\n    .print_section_footer = compact_print_section_footer,\n    .print_integer        = compact_print_int,\n    .print_string         = compact_print_str,\n    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,\n    .priv_class           = &compact_class,\n};\n\n/* CSV output */\n\n#undef OFFSET\n#define OFFSET(x) offsetof(CompactContext, x)\n\nstatic const AVOption csv_options[] = {\n    {\"item_sep\", \"set item separator\",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=\",\"},  0, 0 },\n    {\"s\",        \"set item separator\",    OFFSET(item_sep_str),    AV_OPT_TYPE_STRING, {.str=\",\"},  0, 0 },\n    {\"nokey\",    \"force no key printing\", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {\"nk\",       \"force no key printing\", OFFSET(nokey),           AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {\"escape\",   \"set escape mode\",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str=\"csv\"}, 0, 0 },\n    {\"e\",        \"set escape mode\",       OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str=\"csv\"}, 0, 0 },\n    {\"print_section\", \"print section name\", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {\"p\",             \"print section name\", OFFSET(print_section), AV_OPT_TYPE_BOOL,   {.i64=1},    0,        1        },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(csv);\n\nstatic const Writer csv_writer = {\n    .name                 = \"csv\",\n    .priv_size            = sizeof(CompactContext),\n    .init                 = compact_init,\n    .print_section_header = compact_print_section_header,\n    .print_section_footer = compact_print_section_footer,\n    .print_integer        = compact_print_int,\n    .print_string         = compact_print_str,\n    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,\n    .priv_class           = &csv_class,\n};\n\n/* Flat output */\n\ntypedef struct FlatContext {\n    const AVClass *class;\n    const char *sep_str;\n    char sep;\n    int hierarchical;\n} FlatContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(FlatContext, x)\n\nstatic const AVOption flat_options[]= {\n    {\"sep_char\", \"set separator\",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str=\".\"},  0, 0 },\n    {\"s\",        \"set separator\",    OFFSET(sep_str),    AV_OPT_TYPE_STRING, {.str=\".\"},  0, 0 },\n    {\"hierarchical\", \"specify if the section specification should be hierarchical\", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },\n    {\"h\",            \"specify if the section specification should be hierarchical\", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(flat);\n\nstatic av_cold int flat_init(WriterContext *wctx)\n{\n    FlatContext *flat = wctx->priv;\n\n    if (strlen(flat->sep_str) != 1) {\n        av_log(wctx, AV_LOG_ERROR, \"Item separator '%s' specified, but must contain a single character\\n\",\n               flat->sep_str);\n        return AVERROR(EINVAL);\n    }\n    flat->sep = flat->sep_str[0];\n\n    return 0;\n}\n\nstatic const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)\n{\n    const char *p;\n\n    for (p = src; *p; p++) {\n        if (!((*p >= '0' && *p <= '9') ||\n              (*p >= 'a' && *p <= 'z') ||\n              (*p >= 'A' && *p <= 'Z')))\n            av_bprint_chars(dst, '_', 1);\n        else\n            av_bprint_chars(dst, *p, 1);\n    }\n    return dst->str;\n}\n\nstatic const char *flat_escape_value_str(AVBPrint *dst, const char *src)\n{\n    const char *p;\n\n    for (p = src; *p; p++) {\n        switch (*p) {\n        case '\\n': av_bprintf(dst, \"%s\", \"\\\\n\");  break;\n        case '\\r': av_bprintf(dst, \"%s\", \"\\\\r\");  break;\n        case '\\\\': av_bprintf(dst, \"%s\", \"\\\\\\\\\"); break;\n        case '\"':  av_bprintf(dst, \"%s\", \"\\\\\\\"\"); break;\n        case '`':  av_bprintf(dst, \"%s\", \"\\\\`\");  break;\n        case '$':  av_bprintf(dst, \"%s\", \"\\\\$\");  break;\n        default:   av_bprint_chars(dst, *p, 1);   break;\n        }\n    }\n    return dst->str;\n}\n\nstatic void flat_print_section_header(WriterContext *wctx)\n{\n    FlatContext *flat = wctx->priv;\n    AVBPrint *buf = &wctx->section_pbuf[wctx->level];\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    /* build section header */\n    av_bprint_clear(buf);\n    if (!parent_section)\n        return;\n    av_bprintf(buf, \"%s\", wctx->section_pbuf[wctx->level-1].str);\n\n    if (flat->hierarchical ||\n        !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {\n        av_bprintf(buf, \"%s%s\", wctx->section[wctx->level]->name, flat->sep_str);\n\n        if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {\n            int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?\n                wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];\n            av_bprintf(buf, \"%d%s\", n, flat->sep_str);\n        }\n    }\n}\n\nstatic void flat_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    writer_printf(wctx, \"%s%s=%lld\\n\", wctx->section_pbuf[wctx->level].str, key, value);\n}\n\nstatic void flat_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    FlatContext *flat = wctx->priv;\n    AVBPrint buf;\n\n    writer_put_str(wctx, wctx->section_pbuf[wctx->level].str);\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n    writer_printf(wctx, \"%s=\", flat_escape_key_str(&buf, key, flat->sep));\n    av_bprint_clear(&buf);\n    writer_printf(wctx, \"\\\"%s\\\"\\n\", flat_escape_value_str(&buf, value));\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic const Writer flat_writer = {\n    .name                  = \"flat\",\n    .priv_size             = sizeof(FlatContext),\n    .init                  = flat_init,\n    .print_section_header  = flat_print_section_header,\n    .print_integer         = flat_print_int,\n    .print_string          = flat_print_str,\n    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,\n    .priv_class            = &flat_class,\n};\n\n/* INI format output */\n\ntypedef struct INIContext {\n    const AVClass *class;\n    int hierarchical;\n} INIContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(INIContext, x)\n\nstatic const AVOption ini_options[] = {\n    {\"hierarchical\", \"specify if the section specification should be hierarchical\", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },\n    {\"h\",            \"specify if the section specification should be hierarchical\", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(ini);\n\nstatic char *ini_escape_str(AVBPrint *dst, const char *src)\n{\n    int i = 0;\n    char c = 0;\n\n    while (c = src[i++]) {\n        switch (c) {\n        case '\\b': av_bprintf(dst, \"%s\", \"\\\\b\"); break;\n        case '\\f': av_bprintf(dst, \"%s\", \"\\\\f\"); break;\n        case '\\n': av_bprintf(dst, \"%s\", \"\\\\n\"); break;\n        case '\\r': av_bprintf(dst, \"%s\", \"\\\\r\"); break;\n        case '\\t': av_bprintf(dst, \"%s\", \"\\\\t\"); break;\n        case '\\\\':\n        case '#' :\n        case '=' :\n        case ':' : av_bprint_chars(dst, '\\\\', 1);\n        default:\n            if ((unsigned char)c < 32)\n                av_bprintf(dst, \"\\\\x00%02x\", c & 0xff);\n            else\n                av_bprint_chars(dst, c, 1);\n            break;\n        }\n    }\n    return dst->str;\n}\n\nstatic void ini_print_section_header(WriterContext *wctx)\n{\n    INIContext *ini = wctx->priv;\n    AVBPrint *buf = &wctx->section_pbuf[wctx->level];\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    av_bprint_clear(buf);\n    if (!parent_section) {\n        writer_put_str(wctx, \"# ffprobe output\\n\\n\");\n        return;\n    }\n\n    if (wctx->nb_item[wctx->level-1])\n        writer_w8(wctx, '\\n');\n\n    av_bprintf(buf, \"%s\", wctx->section_pbuf[wctx->level-1].str);\n    if (ini->hierarchical ||\n        !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {\n        av_bprintf(buf, \"%s%s\", buf->str[0] ? \".\" : \"\", wctx->section[wctx->level]->name);\n\n        if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {\n            int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?\n                wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];\n            av_bprintf(buf, \".%d\", n);\n        }\n    }\n\n    if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))\n        writer_printf(wctx, \"[%s]\\n\", buf->str);\n}\n\nstatic void ini_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    AVBPrint buf;\n\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n    writer_printf(wctx, \"%s=\", ini_escape_str(&buf, key));\n    av_bprint_clear(&buf);\n    writer_printf(wctx, \"%s\\n\", ini_escape_str(&buf, value));\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic void ini_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    writer_printf(wctx, \"%s=%lld\\n\", key, value);\n}\n\nstatic const Writer ini_writer = {\n    .name                  = \"ini\",\n    .priv_size             = sizeof(INIContext),\n    .print_section_header  = ini_print_section_header,\n    .print_integer         = ini_print_int,\n    .print_string          = ini_print_str,\n    .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,\n    .priv_class            = &ini_class,\n};\n\n/* JSON output */\n\ntypedef struct JSONContext {\n    const AVClass *class;\n    int indent_level;\n    int compact;\n    const char *item_sep, *item_start_end;\n} JSONContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(JSONContext, x)\n\nstatic const AVOption json_options[]= {\n    { \"compact\", \"enable compact output\", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    { \"c\",       \"enable compact output\", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },\n    { NULL }\n};\n\nDEFINE_WRITER_CLASS(json);\n\nstatic av_cold int json_init(WriterContext *wctx)\n{\n    JSONContext *json = wctx->priv;\n\n    json->item_sep       = json->compact ? \", \" : \",\\n\";\n    json->item_start_end = json->compact ? \" \"  : \"\\n\";\n\n    return 0;\n}\n\nstatic const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)\n{\n    static const char json_escape[] = {'\"', '\\\\', '\\b', '\\f', '\\n', '\\r', '\\t', 0};\n    static const char json_subst[]  = {'\"', '\\\\',  'b',  'f',  'n',  'r',  't', 0};\n    const char *p;\n\n    for (p = src; *p; p++) {\n        char *s = strchr(json_escape, *p);\n        if (s) {\n            av_bprint_chars(dst, '\\\\', 1);\n            av_bprint_chars(dst, json_subst[s - json_escape], 1);\n        } else if ((unsigned char)*p < 32) {\n            av_bprintf(dst, \"\\\\u00%02x\", *p & 0xff);\n        } else {\n            av_bprint_chars(dst, *p, 1);\n        }\n    }\n    return dst->str;\n}\n\n#define JSON_INDENT() writer_printf(wctx, \"%*c\", json->indent_level * 4, ' ')\n\nstatic void json_print_section_header(WriterContext *wctx)\n{\n    JSONContext *json = wctx->priv;\n    AVBPrint buf;\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    if (wctx->level && wctx->nb_item[wctx->level-1])\n        writer_put_str(wctx, \",\\n\");\n\n    if (section->flags & SECTION_FLAG_IS_WRAPPER) {\n        writer_put_str(wctx, \"{\\n\");\n        json->indent_level++;\n    } else {\n        av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n        json_escape_str(&buf, section->name, wctx);\n        JSON_INDENT();\n\n        json->indent_level++;\n        if (section->flags & SECTION_FLAG_IS_ARRAY) {\n            writer_printf(wctx, \"\\\"%s\\\": [\\n\", buf.str);\n        } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {\n            writer_printf(wctx, \"\\\"%s\\\": {%s\", buf.str, json->item_start_end);\n        } else {\n            writer_printf(wctx, \"{%s\", json->item_start_end);\n\n            /* this is required so the parser can distinguish between packets and frames */\n            if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {\n                if (!json->compact)\n                    JSON_INDENT();\n                writer_printf(wctx, \"\\\"type\\\": \\\"%s\\\"\", section->name);\n                wctx->nb_item[wctx->level]++;\n            }\n        }\n        av_bprint_finalize(&buf, NULL);\n    }\n}\n\nstatic void json_print_section_footer(WriterContext *wctx)\n{\n    JSONContext *json = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n\n    if (wctx->level == 0) {\n        json->indent_level--;\n        writer_put_str(wctx, \"\\n}\\n\");\n    } else if (section->flags & SECTION_FLAG_IS_ARRAY) {\n        writer_w8(wctx, '\\n');\n        json->indent_level--;\n        JSON_INDENT();\n        writer_w8(wctx, ']');\n    } else {\n        writer_put_str(wctx, json->item_start_end);\n        json->indent_level--;\n        if (!json->compact)\n            JSON_INDENT();\n        writer_w8(wctx, '}');\n    }\n}\n\nstatic inline void json_print_item_str(WriterContext *wctx,\n                                       const char *key, const char *value)\n{\n    AVBPrint buf;\n\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n    writer_printf(wctx, \"\\\"%s\\\":\", json_escape_str(&buf, key,   wctx));\n    av_bprint_clear(&buf);\n    writer_printf(wctx, \" \\\"%s\\\"\", json_escape_str(&buf, value, wctx));\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic void json_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    JSONContext *json = wctx->priv;\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))\n        writer_put_str(wctx, json->item_sep);\n    if (!json->compact)\n        JSON_INDENT();\n    json_print_item_str(wctx, key, value);\n}\n\nstatic void json_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    JSONContext *json = wctx->priv;\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n    AVBPrint buf;\n\n    if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES))\n        writer_put_str(wctx, json->item_sep);\n    if (!json->compact)\n        JSON_INDENT();\n\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n    writer_printf(wctx, \"\\\"%s\\\": %lld\", json_escape_str(&buf, key, wctx), value);\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic const Writer json_writer = {\n    .name                 = \"json\",\n    .priv_size            = sizeof(JSONContext),\n    .init                 = json_init,\n    .print_section_header = json_print_section_header,\n    .print_section_footer = json_print_section_footer,\n    .print_integer        = json_print_int,\n    .print_string         = json_print_str,\n    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,\n    .priv_class           = &json_class,\n};\n\n/* XML output */\n\ntypedef struct XMLContext {\n    const AVClass *class;\n    int within_tag;\n    int indent_level;\n    int fully_qualified;\n    int xsd_strict;\n} XMLContext;\n\n#undef OFFSET\n#define OFFSET(x) offsetof(XMLContext, x)\n\nstatic const AVOption xml_options[] = {\n    {\"fully_qualified\", \"specify if the output should be fully qualified\", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },\n    {\"q\",               \"specify if the output should be fully qualified\", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },\n    {\"xsd_strict\",      \"ensure that the output is XSD compliant\",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },\n    {\"x\",               \"ensure that the output is XSD compliant\",         OFFSET(xsd_strict),      AV_OPT_TYPE_BOOL, {.i64=0},  0, 1 },\n    {NULL},\n};\n\nDEFINE_WRITER_CLASS(xml);\n\nstatic av_cold int xml_init(WriterContext *wctx)\n{\n    XMLContext *xml = wctx->priv;\n\n    if (xml->xsd_strict) {\n        xml->fully_qualified = 1;\n#define CHECK_COMPLIANCE(opt, opt_name)                                 \\\n        if (opt) {                                                      \\\n            av_log(wctx, AV_LOG_ERROR,                                  \\\n                   \"XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\\n\" \\\n                   \"You need to disable such option with '-no%s'\\n\", opt_name, opt_name); \\\n            return AVERROR(EINVAL);                                     \\\n        }\n        CHECK_COMPLIANCE(show_private_data, \"private\");\n        CHECK_COMPLIANCE(show_value_unit,   \"unit\");\n        CHECK_COMPLIANCE(use_value_prefix,  \"prefix\");\n    }\n\n    return 0;\n}\n\n#define XML_INDENT() writer_printf(wctx, \"%*c\", xml->indent_level * 4, ' ')\n\nstatic void xml_print_section_header(WriterContext *wctx)\n{\n    XMLContext *xml = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n    const struct section *parent_section = wctx->level ?\n        wctx->section[wctx->level-1] : NULL;\n\n    if (wctx->level == 0) {\n        const char *qual = \" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\" \"\n            \"xmlns:ffprobe=\\\"http://www.ffmpeg.org/schema/ffprobe\\\" \"\n            \"xsi:schemaLocation=\\\"http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd\\\"\";\n\n        writer_put_str(wctx, \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\");\n        writer_printf(wctx, \"<%sffprobe%s>\\n\",\n               xml->fully_qualified ? \"ffprobe:\" : \"\",\n               xml->fully_qualified ? qual : \"\");\n        return;\n    }\n\n    if (xml->within_tag) {\n        xml->within_tag = 0;\n        writer_put_str(wctx, \">\\n\");\n    }\n    if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {\n        xml->indent_level++;\n    } else {\n        if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&\n            wctx->level && wctx->nb_item[wctx->level-1])\n            writer_w8(wctx, '\\n');\n        xml->indent_level++;\n\n        if (section->flags & SECTION_FLAG_IS_ARRAY) {\n            XML_INDENT(); writer_printf(wctx, \"<%s>\\n\", section->name);\n        } else {\n            XML_INDENT(); writer_printf(wctx, \"<%s \", section->name);\n            xml->within_tag = 1;\n        }\n    }\n}\n\nstatic void xml_print_section_footer(WriterContext *wctx)\n{\n    XMLContext *xml = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n\n    if (wctx->level == 0) {\n        writer_printf(wctx, \"</%sffprobe>\\n\", xml->fully_qualified ? \"ffprobe:\" : \"\");\n    } else if (xml->within_tag) {\n        xml->within_tag = 0;\n        writer_put_str(wctx, \"/>\\n\");\n        xml->indent_level--;\n    } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {\n        xml->indent_level--;\n    } else {\n        XML_INDENT(); writer_printf(wctx, \"</%s>\\n\", section->name);\n        xml->indent_level--;\n    }\n}\n\nstatic void xml_print_str(WriterContext *wctx, const char *key, const char *value)\n{\n    AVBPrint buf;\n    XMLContext *xml = wctx->priv;\n    const struct section *section = wctx->section[wctx->level];\n\n    av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {\n        XML_INDENT();\n        av_bprint_escape(&buf, key, NULL,\n                         AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);\n        writer_printf(wctx, \"<%s key=\\\"%s\\\"\",\n                      section->element_name, buf.str);\n        av_bprint_clear(&buf);\n\n        av_bprint_escape(&buf, value, NULL,\n                         AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);\n        writer_printf(wctx, \" value=\\\"%s\\\"/>\\n\", buf.str);\n    } else {\n        if (wctx->nb_item[wctx->level])\n            writer_w8(wctx, ' ');\n\n        av_bprint_escape(&buf, value, NULL,\n                         AV_ESCAPE_MODE_XML, AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES);\n        writer_printf(wctx, \"%s=\\\"%s\\\"\", key, buf.str);\n    }\n\n    av_bprint_finalize(&buf, NULL);\n}\n\nstatic void xml_print_int(WriterContext *wctx, const char *key, long long int value)\n{\n    if (wctx->nb_item[wctx->level])\n        writer_w8(wctx, ' ');\n    writer_printf(wctx, \"%s=\\\"%lld\\\"\", key, value);\n}\n\nstatic Writer xml_writer = {\n    .name                 = \"xml\",\n    .priv_size            = sizeof(XMLContext),\n    .init                 = xml_init,\n    .print_section_header = xml_print_section_header,\n    .print_section_footer = xml_print_section_footer,\n    .print_integer        = xml_print_int,\n    .print_string         = xml_print_str,\n    .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,\n    .priv_class           = &xml_class,\n};\n\nstatic void writer_register_all(void)\n{\n    static int initialized;\n\n    if (initialized)\n        return;\n    initialized = 1;\n\n    writer_register(&default_writer);\n    writer_register(&compact_writer);\n    writer_register(&csv_writer);\n    writer_register(&flat_writer);\n    writer_register(&ini_writer);\n    writer_register(&json_writer);\n    writer_register(&xml_writer);\n}\n\n#define print_fmt(k, f, ...) do {              \\\n    av_bprint_clear(&pbuf);                    \\\n    av_bprintf(&pbuf, f, __VA_ARGS__);         \\\n    writer_print_string(w, k, pbuf.str, 0);    \\\n} while (0)\n\n#define print_list_fmt(k, f, n, ...) do {       \\\n    av_bprint_clear(&pbuf);                     \\\n    for (int idx = 0; idx < n; idx++) {         \\\n        if (idx > 0)                            \\\n            av_bprint_chars(&pbuf, ' ', 1);     \\\n        av_bprintf(&pbuf, f, __VA_ARGS__);      \\\n    }                                           \\\n    writer_print_string(w, k, pbuf.str, 0);     \\\n} while (0)\n\n#define print_int(k, v)         writer_print_integer(w, k, v)\n#define print_q(k, v, s)        writer_print_rational(w, k, v, s)\n#define print_str(k, v)         writer_print_string(w, k, v, 0)\n#define print_str_opt(k, v)     writer_print_string(w, k, v, PRINT_STRING_OPT)\n#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)\n#define print_time(k, v, tb)    writer_print_time(w, k, v, tb, 0)\n#define print_ts(k, v)          writer_print_ts(w, k, v, 0)\n#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)\n#define print_duration_ts(k, v)       writer_print_ts(w, k, v, 1)\n#define print_val(k, v, u) do {                                     \\\n    struct unit_value uv;                                           \\\n    uv.val.i = v;                                                   \\\n    uv.unit = u;                                                    \\\n    writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \\\n} while (0)\n\n#define print_section_header(s) writer_print_section_header(w, s)\n#define print_section_footer(s) writer_print_section_footer(w, s)\n\n#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \\\n{                                                                       \\\n    ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \\\n    if (ret < 0)                                                        \\\n        goto end;                                                       \\\n    memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \\\n}\n\nstatic inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)\n{\n    const AVDictionaryEntry *tag = NULL;\n    int ret = 0;\n\n    if (!tags)\n        return 0;\n    writer_print_section_header(w, section_id);\n\n    while ((tag = av_dict_get(tags, \"\", tag, AV_DICT_IGNORE_SUFFIX))) {\n        if ((ret = print_str_validate(tag->key, tag->value)) < 0)\n            break;\n    }\n    writer_print_section_footer(w);\n\n    return ret;\n}\n\nstatic void print_dovi_metadata(WriterContext *w, const AVDOVIMetadata *dovi)\n{\n    if (!dovi)\n        return;\n\n    {\n        const AVDOVIRpuDataHeader *hdr     = av_dovi_get_header(dovi);\n        const AVDOVIDataMapping   *mapping = av_dovi_get_mapping(dovi);\n        const AVDOVIColorMetadata *color   = av_dovi_get_color(dovi);\n        AVBPrint pbuf;\n\n        av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n        // header\n        print_int(\"rpu_type\",        hdr->rpu_type);\n        print_int(\"rpu_format\",      hdr->rpu_format);\n        print_int(\"vdr_rpu_profile\", hdr->vdr_rpu_profile);\n        print_int(\"vdr_rpu_level\",   hdr->vdr_rpu_level);\n        print_int(\"chroma_resampling_explicit_filter_flag\",\n                  hdr->chroma_resampling_explicit_filter_flag);\n        print_int(\"coef_data_type\",           hdr->coef_data_type);\n        print_int(\"coef_log2_denom\",          hdr->coef_log2_denom);\n        print_int(\"vdr_rpu_normalized_idc\",   hdr->vdr_rpu_normalized_idc);\n        print_int(\"bl_video_full_range_flag\", hdr->bl_video_full_range_flag);\n        print_int(\"bl_bit_depth\",             hdr->bl_bit_depth);\n        print_int(\"el_bit_depth\",             hdr->el_bit_depth);\n        print_int(\"vdr_bit_depth\",            hdr->vdr_bit_depth);\n        print_int(\"spatial_resampling_filter_flag\",\n                  hdr->spatial_resampling_filter_flag);\n        print_int(\"el_spatial_resampling_filter_flag\",\n                  hdr->el_spatial_resampling_filter_flag);\n        print_int(\"disable_residual_flag\",     hdr->disable_residual_flag);\n\n        // data mapping values\n        print_int(\"vdr_rpu_id\",                mapping->vdr_rpu_id);\n        print_int(\"mapping_color_space\",       mapping->mapping_color_space);\n        print_int(\"mapping_chroma_format_idc\",\n                  mapping->mapping_chroma_format_idc);\n\n        print_int(\"nlq_method_idc\",            mapping->nlq_method_idc);\n        switch (mapping->nlq_method_idc) {\n        case AV_DOVI_NLQ_NONE:\n            print_str(\"nlq_method_idc_name\", \"none\");\n            break;\n        case AV_DOVI_NLQ_LINEAR_DZ:\n            print_str(\"nlq_method_idc_name\", \"linear_dz\");\n            break;\n        default:\n            print_str(\"nlq_method_idc_name\", \"unknown\");\n            break;\n        }\n\n        print_int(\"num_x_partitions\",          mapping->num_x_partitions);\n        print_int(\"num_y_partitions\",          mapping->num_y_partitions);\n\n        writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST);\n\n        for (int c = 0; c < 3; c++) {\n            const AVDOVIReshapingCurve *curve = &mapping->curves[c];\n            writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_COMPONENT);\n\n            print_list_fmt(\"pivots\", \"%\"PRIu16, curve->num_pivots, curve->pivots[idx]);\n\n            writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST);\n            for (int i = 0; i < curve->num_pivots - 1; i++) {\n\n                writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_PIECE);\n                print_int(\"mapping_idc\", curve->mapping_idc[i]);\n                switch (curve->mapping_idc[i]) {\n                case AV_DOVI_MAPPING_POLYNOMIAL:\n                    print_str(\"mapping_idc_name\",   \"polynomial\");\n                    print_int(\"poly_order\",         curve->poly_order[i]);\n                    print_list_fmt(\"poly_coef\", \"%\"PRIi64,\n                                   curve->poly_order[i] + 1,\n                                   curve->poly_coef[i][idx]);\n                    break;\n                case AV_DOVI_MAPPING_MMR:\n                    print_str(\"mapping_idc_name\",   \"mmr\");\n                    print_int(\"mmr_order\",          curve->mmr_order[i]);\n                    print_int(\"mmr_constant\",       curve->mmr_constant[i]);\n                    print_list_fmt(\"mmr_coef\", \"%\"PRIi64,\n                                   curve->mmr_order[i] * 7,\n                                   curve->mmr_coef[i][0][idx]);\n                    break;\n                default:\n                    print_str(\"mapping_idc_name\",   \"unknown\");\n                    break;\n                }\n\n                // SECTION_ID_FRAME_SIDE_DATA_PIECE\n                writer_print_section_footer(w);\n            }\n\n            // SECTION_ID_FRAME_SIDE_DATA_PIECE_LIST\n            writer_print_section_footer(w);\n\n            if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) {\n                const AVDOVINLQParams *nlq  = &mapping->nlq[c];\n                print_int(\"nlq_offset\", nlq->nlq_offset);\n                print_int(\"vdr_in_max\", nlq->vdr_in_max);\n\n                switch (mapping->nlq_method_idc) {\n                case AV_DOVI_NLQ_LINEAR_DZ:\n                    print_int(\"linear_deadzone_slope\",      nlq->linear_deadzone_slope);\n                    print_int(\"linear_deadzone_threshold\",  nlq->linear_deadzone_threshold);\n                    break;\n                }\n            }\n\n            // SECTION_ID_FRAME_SIDE_DATA_COMPONENT\n            writer_print_section_footer(w);\n        }\n\n        // SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST\n        writer_print_section_footer(w);\n\n        // color metadata\n        print_int(\"dm_metadata_id\",         color->dm_metadata_id);\n        print_int(\"scene_refresh_flag\",     color->scene_refresh_flag);\n        print_list_fmt(\"ycc_to_rgb_matrix\", \"%d/%d\",\n                       FF_ARRAY_ELEMS(color->ycc_to_rgb_matrix),\n                       color->ycc_to_rgb_matrix[idx].num,\n                       color->ycc_to_rgb_matrix[idx].den);\n        print_list_fmt(\"ycc_to_rgb_offset\", \"%d/%d\",\n                       FF_ARRAY_ELEMS(color->ycc_to_rgb_offset),\n                       color->ycc_to_rgb_offset[idx].num,\n                       color->ycc_to_rgb_offset[idx].den);\n        print_list_fmt(\"rgb_to_lms_matrix\", \"%d/%d\",\n                       FF_ARRAY_ELEMS(color->rgb_to_lms_matrix),\n                       color->rgb_to_lms_matrix[idx].num,\n                       color->rgb_to_lms_matrix[idx].den);\n        print_int(\"signal_eotf\",            color->signal_eotf);\n        print_int(\"signal_eotf_param0\",     color->signal_eotf_param0);\n        print_int(\"signal_eotf_param1\",     color->signal_eotf_param1);\n        print_int(\"signal_eotf_param2\",     color->signal_eotf_param2);\n        print_int(\"signal_bit_depth\",       color->signal_bit_depth);\n        print_int(\"signal_color_space\",     color->signal_color_space);\n        print_int(\"signal_chroma_format\",   color->signal_chroma_format);\n        print_int(\"signal_full_range_flag\", color->signal_full_range_flag);\n        print_int(\"source_min_pq\",          color->source_min_pq);\n        print_int(\"source_max_pq\",          color->source_max_pq);\n        print_int(\"source_diagonal\",        color->source_diagonal);\n\n        av_bprint_finalize(&pbuf, NULL);\n    }\n}\n\nstatic void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata)\n{\n    if (!metadata)\n        return;\n    print_int(\"application version\", metadata->application_version);\n    print_int(\"num_windows\", metadata->num_windows);\n    for (int n = 1; n < metadata->num_windows; n++) {\n        const AVHDRPlusColorTransformParams *params = &metadata->params[n];\n        print_q(\"window_upper_left_corner_x\",\n                params->window_upper_left_corner_x,'/');\n        print_q(\"window_upper_left_corner_y\",\n                params->window_upper_left_corner_y,'/');\n        print_q(\"window_lower_right_corner_x\",\n                params->window_lower_right_corner_x,'/');\n        print_q(\"window_lower_right_corner_y\",\n                params->window_lower_right_corner_y,'/');\n        print_q(\"window_upper_left_corner_x\",\n                params->window_upper_left_corner_x,'/');\n        print_q(\"window_upper_left_corner_y\",\n                params->window_upper_left_corner_y,'/');\n        print_int(\"center_of_ellipse_x\",\n                  params->center_of_ellipse_x ) ;\n        print_int(\"center_of_ellipse_y\",\n                  params->center_of_ellipse_y );\n        print_int(\"rotation_angle\",\n                  params->rotation_angle);\n        print_int(\"semimajor_axis_internal_ellipse\",\n                  params->semimajor_axis_internal_ellipse);\n        print_int(\"semimajor_axis_external_ellipse\",\n                  params->semimajor_axis_external_ellipse);\n        print_int(\"semiminor_axis_external_ellipse\",\n                  params->semiminor_axis_external_ellipse);\n        print_int(\"overlap_process_option\",\n                  params->overlap_process_option);\n    }\n    print_q(\"targeted_system_display_maximum_luminance\",\n            metadata->targeted_system_display_maximum_luminance,'/');\n    if (metadata->targeted_system_display_actual_peak_luminance_flag) {\n        print_int(\"num_rows_targeted_system_display_actual_peak_luminance\",\n                  metadata->num_rows_targeted_system_display_actual_peak_luminance);\n        print_int(\"num_cols_targeted_system_display_actual_peak_luminance\",\n                  metadata->num_cols_targeted_system_display_actual_peak_luminance);\n        for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) {\n            for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) {\n                print_q(\"targeted_system_display_actual_peak_luminance\",\n                        metadata->targeted_system_display_actual_peak_luminance[i][j],'/');\n            }\n        }\n    }\n    for (int n = 0; n < metadata->num_windows; n++) {\n        const AVHDRPlusColorTransformParams *params = &metadata->params[n];\n        for (int i = 0; i < 3; i++) {\n            print_q(\"maxscl\",params->maxscl[i],'/');\n        }\n        print_q(\"average_maxrgb\",\n                params->average_maxrgb,'/');\n        print_int(\"num_distribution_maxrgb_percentiles\",\n                  params->num_distribution_maxrgb_percentiles);\n        for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) {\n            print_int(\"distribution_maxrgb_percentage\",\n                      params->distribution_maxrgb[i].percentage);\n            print_q(\"distribution_maxrgb_percentile\",\n                    params->distribution_maxrgb[i].percentile,'/');\n        }\n        print_q(\"fraction_bright_pixels\",\n                params->fraction_bright_pixels,'/');\n    }\n    if (metadata->mastering_display_actual_peak_luminance_flag) {\n        print_int(\"num_rows_mastering_display_actual_peak_luminance\",\n                  metadata->num_rows_mastering_display_actual_peak_luminance);\n        print_int(\"num_cols_mastering_display_actual_peak_luminance\",\n                  metadata->num_cols_mastering_display_actual_peak_luminance);\n        for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) {\n            for (int j = 0; j <  metadata->num_cols_mastering_display_actual_peak_luminance; j++) {\n                print_q(\"mastering_display_actual_peak_luminance\",\n                        metadata->mastering_display_actual_peak_luminance[i][j],'/');\n            }\n        }\n    }\n\n    for (int n = 0; n < metadata->num_windows; n++) {\n        const AVHDRPlusColorTransformParams *params = &metadata->params[n];\n        if (params->tone_mapping_flag) {\n            print_q(\"knee_point_x\", params->knee_point_x,'/');\n            print_q(\"knee_point_y\", params->knee_point_y,'/');\n            print_int(\"num_bezier_curve_anchors\",\n                      params->num_bezier_curve_anchors );\n            for (int i = 0; i < params->num_bezier_curve_anchors; i++) {\n                print_q(\"bezier_curve_anchors\",\n                        params->bezier_curve_anchors[i],'/');\n            }\n        }\n        if (params->color_saturation_mapping_flag) {\n            print_q(\"color_saturation_weight\",\n                    params->color_saturation_weight,'/');\n        }\n    }\n}\n\nstatic void print_dynamic_hdr_vivid(WriterContext *w, const AVDynamicHDRVivid *metadata)\n{\n    if (!metadata)\n        return;\n    print_int(\"system_start_code\", metadata->system_start_code);\n    print_int(\"num_windows\", metadata->num_windows);\n\n    for (int n = 0; n < metadata->num_windows; n++) {\n        const AVHDRVividColorTransformParams *params = &metadata->params[n];\n\n        print_q(\"minimum_maxrgb\", params->minimum_maxrgb, '/');\n        print_q(\"average_maxrgb\", params->average_maxrgb, '/');\n        print_q(\"variance_maxrgb\", params->variance_maxrgb, '/');\n        print_q(\"maximum_maxrgb\", params->maximum_maxrgb, '/');\n    }\n\n    for (int n = 0; n < metadata->num_windows; n++) {\n        const AVHDRVividColorTransformParams *params = &metadata->params[n];\n\n        print_int(\"tone_mapping_mode_flag\", params->tone_mapping_mode_flag);\n        print_int(\"tone_mapping_param_num\", params->tone_mapping_param_num);\n        if (params->tone_mapping_mode_flag) {\n            for (int i = 0; i < params->tone_mapping_param_num; i++) {\n                const AVHDRVividColorToneMappingParams *tm_params = &params->tm_params[i];\n\n                print_q(\"targeted_system_display_maximum_luminance\",\n                        tm_params->targeted_system_display_maximum_luminance, '/');\n                print_int(\"base_enable_flag\", tm_params->base_enable_flag);\n                if (tm_params->base_enable_flag) {\n                    print_q(\"base_param_m_p\", tm_params->base_param_m_p, '/');\n                    print_q(\"base_param_m_m\", tm_params->base_param_m_m, '/');\n                    print_q(\"base_param_m_a\", tm_params->base_param_m_a, '/');\n                    print_q(\"base_param_m_b\", tm_params->base_param_m_b, '/');\n                    print_q(\"base_param_m_n\", tm_params->base_param_m_n, '/');\n\n                    print_int(\"base_param_k1\", tm_params->base_param_k1);\n                    print_int(\"base_param_k2\", tm_params->base_param_k2);\n                    print_int(\"base_param_k3\", tm_params->base_param_k3);\n                    print_int(\"base_param_Delta_enable_mode\",\n                              tm_params->base_param_Delta_enable_mode);\n                    print_q(\"base_param_Delta\", tm_params->base_param_Delta, '/');\n                }\n                print_int(\"3Spline_enable_flag\", tm_params->three_Spline_enable_flag);\n                if (tm_params->three_Spline_enable_flag) {\n                    print_int(\"3Spline_num\", tm_params->three_Spline_num);\n                    print_int(\"3Spline_TH_mode\", tm_params->three_Spline_TH_mode);\n\n                    for (int j = 0; j < tm_params->three_Spline_num; j++) {\n                        print_q(\"3Spline_TH_enable_MB\", tm_params->three_Spline_TH_enable_MB, '/');\n                        print_q(\"3Spline_TH_enable\", tm_params->three_Spline_TH_enable, '/');\n                        print_q(\"3Spline_TH_Delta1\", tm_params->three_Spline_TH_Delta1, '/');\n                        print_q(\"3Spline_TH_Delta2\", tm_params->three_Spline_TH_Delta2, '/');\n                        print_q(\"3Spline_enable_Strength\", tm_params->three_Spline_enable_Strength, '/');\n                    }\n                }\n            }\n        }\n\n        print_int(\"color_saturation_mapping_flag\", params->color_saturation_mapping_flag);\n        if (params->color_saturation_mapping_flag) {\n            print_int(\"color_saturation_num\", params->color_saturation_num);\n            for (int i = 0; i < params->color_saturation_num; i++) {\n                print_q(\"color_saturation_gain\", params->color_saturation_gain[i], '/');\n            }\n        }\n    }\n}\n\nstatic void print_pkt_side_data(WriterContext *w,\n                                AVCodecParameters *par,\n                                const AVPacketSideData *side_data,\n                                int nb_side_data,\n                                SectionID id_data_list,\n                                SectionID id_data)\n{\n    int i;\n\n    writer_print_section_header(w, id_data_list);\n    for (i = 0; i < nb_side_data; i++) {\n        const AVPacketSideData *sd = &side_data[i];\n        const char *name = av_packet_side_data_name(sd->type);\n\n        writer_print_section_header(w, id_data);\n        print_str(\"side_data_type\", name ? name : \"unknown\");\n        if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {\n            writer_print_integers(w, \"displaymatrix\", sd->data, 9, \" %11d\", 3, 4, 1);\n            print_int(\"rotation\", av_display_rotation_get((int32_t *)sd->data));\n        } else if (sd->type == AV_PKT_DATA_STEREO3D) {\n            const AVStereo3D *stereo = (AVStereo3D *)sd->data;\n            print_str(\"type\", av_stereo3d_type_name(stereo->type));\n            print_int(\"inverted\", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));\n        } else if (sd->type == AV_PKT_DATA_SPHERICAL) {\n            const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;\n            print_str(\"projection\", av_spherical_projection_name(spherical->projection));\n            if (spherical->projection == AV_SPHERICAL_CUBEMAP) {\n                print_int(\"padding\", spherical->padding);\n            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {\n                size_t l, t, r, b;\n                av_spherical_tile_bounds(spherical, par->width, par->height,\n                                         &l, &t, &r, &b);\n                print_int(\"bound_left\", l);\n                print_int(\"bound_top\", t);\n                print_int(\"bound_right\", r);\n                print_int(\"bound_bottom\", b);\n            }\n\n            print_int(\"yaw\", (double) spherical->yaw / (1 << 16));\n            print_int(\"pitch\", (double) spherical->pitch / (1 << 16));\n            print_int(\"roll\", (double) spherical->roll / (1 << 16));\n        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {\n            print_int(\"skip_samples\",    AV_RL32(sd->data));\n            print_int(\"discard_padding\", AV_RL32(sd->data + 4));\n            print_int(\"skip_reason\",     AV_RL8(sd->data + 8));\n            print_int(\"discard_reason\",  AV_RL8(sd->data + 9));\n        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {\n            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;\n\n            if (metadata->has_primaries) {\n                print_q(\"red_x\", metadata->display_primaries[0][0], '/');\n                print_q(\"red_y\", metadata->display_primaries[0][1], '/');\n                print_q(\"green_x\", metadata->display_primaries[1][0], '/');\n                print_q(\"green_y\", metadata->display_primaries[1][1], '/');\n                print_q(\"blue_x\", metadata->display_primaries[2][0], '/');\n                print_q(\"blue_y\", metadata->display_primaries[2][1], '/');\n\n                print_q(\"white_point_x\", metadata->white_point[0], '/');\n                print_q(\"white_point_y\", metadata->white_point[1], '/');\n            }\n\n            if (metadata->has_luminance) {\n                print_q(\"min_luminance\", metadata->min_luminance, '/');\n                print_q(\"max_luminance\", metadata->max_luminance, '/');\n            }\n        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {\n            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;\n            print_int(\"max_content\", metadata->MaxCLL);\n            print_int(\"max_average\", metadata->MaxFALL);\n        } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {\n            AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;\n            print_int(\"dv_version_major\", dovi->dv_version_major);\n            print_int(\"dv_version_minor\", dovi->dv_version_minor);\n            print_int(\"dv_profile\", dovi->dv_profile);\n            print_int(\"dv_level\", dovi->dv_level);\n            print_int(\"rpu_present_flag\", dovi->rpu_present_flag);\n            print_int(\"el_present_flag\", dovi->el_present_flag);\n            print_int(\"bl_present_flag\", dovi->bl_present_flag);\n            print_int(\"dv_bl_signal_compatibility_id\", dovi->dv_bl_signal_compatibility_id);\n        } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {\n            enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;\n            print_int(\"service_type\", *t);\n        } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {\n            print_int(\"id\", *sd->data);\n        } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {\n            const AVCPBProperties *prop = (AVCPBProperties *)sd->data;\n            print_int(\"max_bitrate\", prop->max_bitrate);\n            print_int(\"min_bitrate\", prop->min_bitrate);\n            print_int(\"avg_bitrate\", prop->avg_bitrate);\n            print_int(\"buffer_size\", prop->buffer_size);\n            print_int(\"vbv_delay\",   prop->vbv_delay);\n        } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||\n                   sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {\n            if (do_show_data)\n                writer_print_data(w, \"data\", sd->data, sd->size);\n            writer_print_data_hash(w, \"data_hash\", sd->data, sd->size);\n        } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {\n            print_int(\"active_format\", *sd->data);\n        }\n        writer_print_section_footer(w);\n    }\n    writer_print_section_footer(w);\n}\n\nstatic void print_color_range(WriterContext *w, enum AVColorRange color_range)\n{\n    const char *val = av_color_range_name(color_range);\n    if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) {\n        print_str_opt(\"color_range\", \"unknown\");\n    } else {\n        print_str(\"color_range\", val);\n    }\n}\n\nstatic void print_color_space(WriterContext *w, enum AVColorSpace color_space)\n{\n    const char *val = av_color_space_name(color_space);\n    if (!val || color_space == AVCOL_SPC_UNSPECIFIED) {\n        print_str_opt(\"color_space\", \"unknown\");\n    } else {\n        print_str(\"color_space\", val);\n    }\n}\n\nstatic void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries)\n{\n    const char *val = av_color_primaries_name(color_primaries);\n    if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) {\n        print_str_opt(\"color_primaries\", \"unknown\");\n    } else {\n        print_str(\"color_primaries\", val);\n    }\n}\n\nstatic void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc)\n{\n    const char *val = av_color_transfer_name(color_trc);\n    if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) {\n        print_str_opt(\"color_transfer\", \"unknown\");\n    } else {\n        print_str(\"color_transfer\", val);\n    }\n}\n\nstatic void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location)\n{\n    const char *val = av_chroma_location_name(chroma_location);\n    if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) {\n        print_str_opt(\"chroma_location\", \"unspecified\");\n    } else {\n        print_str(\"chroma_location\", val);\n    }\n}\n\n\nstatic void clear_log(int need_lock)\n{\n    int i;\n\n    if (need_lock)\n        pthread_mutex_lock(&log_mutex);\n    for (i=0; i<log_buffer_size; i++) {\n        av_freep(&log_buffer[i].context_name);\n        av_freep(&log_buffer[i].parent_name);\n        av_freep(&log_buffer[i].log_message);\n    }\n    log_buffer_size = 0;\n    if(need_lock)\n        pthread_mutex_unlock(&log_mutex);\n}\n\nstatic int show_log(WriterContext *w, int section_ids, int section_id, int log_level)\n{\n    int i;\n    pthread_mutex_lock(&log_mutex);\n    if (!log_buffer_size) {\n        pthread_mutex_unlock(&log_mutex);\n        return 0;\n    }\n    writer_print_section_header(w, section_ids);\n\n    for (i=0; i<log_buffer_size; i++) {\n        if (log_buffer[i].log_level <= log_level) {\n            writer_print_section_header(w, section_id);\n            print_str(\"context\", log_buffer[i].context_name);\n            print_int(\"level\", log_buffer[i].log_level);\n            print_int(\"category\", log_buffer[i].category);\n            if (log_buffer[i].parent_name) {\n                print_str(\"parent_context\", log_buffer[i].parent_name);\n                print_int(\"parent_category\", log_buffer[i].parent_category);\n            } else {\n                print_str_opt(\"parent_context\", \"N/A\");\n                print_str_opt(\"parent_category\", \"N/A\");\n            }\n            print_str(\"message\", log_buffer[i].log_message);\n            writer_print_section_footer(w);\n        }\n    }\n    clear_log(0);\n    pthread_mutex_unlock(&log_mutex);\n\n    writer_print_section_footer(w);\n\n    return 0;\n}\n\nstatic void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx)\n{\n    char val_str[128];\n    AVStream *st = ifile->streams[pkt->stream_index].st;\n    AVBPrint pbuf;\n    const char *s;\n\n    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    writer_print_section_header(w, SECTION_ID_PACKET);\n\n    s = av_get_media_type_string(st->codecpar->codec_type);\n    if (s) print_str    (\"codec_type\", s);\n    else   print_str_opt(\"codec_type\", \"unknown\");\n    print_int(\"stream_index\",     pkt->stream_index);\n    print_ts  (\"pts\",             pkt->pts);\n    print_time(\"pts_time\",        pkt->pts, &st->time_base);\n    print_ts  (\"dts\",             pkt->dts);\n    print_time(\"dts_time\",        pkt->dts, &st->time_base);\n    print_duration_ts(\"duration\",        pkt->duration);\n    print_duration_time(\"duration_time\", pkt->duration, &st->time_base);\n    print_val(\"size\",             pkt->size, unit_byte_str);\n    if (pkt->pos != -1) print_fmt    (\"pos\", \"%\"PRId64, pkt->pos);\n    else                print_str_opt(\"pos\", \"N/A\");\n    print_fmt(\"flags\", \"%c%c\",      pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',\n              pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_');\n\n    if (pkt->side_data_elems) {\n        size_t size;\n        const uint8_t *side_metadata;\n\n        side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);\n        if (side_metadata && size && do_show_packet_tags) {\n            AVDictionary *dict = NULL;\n            if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)\n                show_tags(w, dict, SECTION_ID_PACKET_TAGS);\n            av_dict_free(&dict);\n        }\n\n        print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems,\n                            SECTION_ID_PACKET_SIDE_DATA_LIST,\n                            SECTION_ID_PACKET_SIDE_DATA);\n    }\n\n    if (do_show_data)\n        writer_print_data(w, \"data\", pkt->data, pkt->size);\n    writer_print_data_hash(w, \"data_hash\", pkt->data, pkt->size);\n    writer_print_section_footer(w);\n\n    av_bprint_finalize(&pbuf, NULL);\n    fflush(stdout);\n}\n\nstatic void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,\n                          AVFormatContext *fmt_ctx)\n{\n    AVBPrint pbuf;\n\n    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    writer_print_section_header(w, SECTION_ID_SUBTITLE);\n\n    print_str (\"media_type\",         \"subtitle\");\n    print_ts  (\"pts\",                 sub->pts);\n    print_time(\"pts_time\",            sub->pts, &AV_TIME_BASE_Q);\n    print_int (\"format\",              sub->format);\n    print_int (\"start_display_time\",  sub->start_display_time);\n    print_int (\"end_display_time\",    sub->end_display_time);\n    print_int (\"num_rects\",           sub->num_rects);\n\n    writer_print_section_footer(w);\n\n    av_bprint_finalize(&pbuf, NULL);\n    fflush(stdout);\n}\n\nstatic void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,\n                       AVFormatContext *fmt_ctx)\n{\n    AVBPrint pbuf;\n    char val_str[128];\n    const char *s;\n    int i;\n\n    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    writer_print_section_header(w, SECTION_ID_FRAME);\n\n    s = av_get_media_type_string(stream->codecpar->codec_type);\n    if (s) print_str    (\"media_type\", s);\n    else   print_str_opt(\"media_type\", \"unknown\");\n    print_int(\"stream_index\",           stream->index);\n    print_int(\"key_frame\",              frame->key_frame);\n    print_ts  (\"pts\",                   frame->pts);\n    print_time(\"pts_time\",              frame->pts, &stream->time_base);\n    print_ts  (\"pkt_dts\",               frame->pkt_dts);\n    print_time(\"pkt_dts_time\",          frame->pkt_dts, &stream->time_base);\n    print_ts  (\"best_effort_timestamp\", frame->best_effort_timestamp);\n    print_time(\"best_effort_timestamp_time\", frame->best_effort_timestamp, &stream->time_base);\n    print_duration_ts  (\"pkt_duration\",      frame->pkt_duration);\n    print_duration_time(\"pkt_duration_time\", frame->pkt_duration, &stream->time_base);\n    if (frame->pkt_pos != -1) print_fmt    (\"pkt_pos\", \"%\"PRId64, frame->pkt_pos);\n    else                      print_str_opt(\"pkt_pos\", \"N/A\");\n    if (frame->pkt_size != -1) print_val    (\"pkt_size\", frame->pkt_size, unit_byte_str);\n    else                       print_str_opt(\"pkt_size\", \"N/A\");\n\n    switch (stream->codecpar->codec_type) {\n        AVRational sar;\n\n    case AVMEDIA_TYPE_VIDEO:\n        print_int(\"width\",                  frame->width);\n        print_int(\"height\",                 frame->height);\n        s = av_get_pix_fmt_name(frame->format);\n        if (s) print_str    (\"pix_fmt\", s);\n        else   print_str_opt(\"pix_fmt\", \"unknown\");\n        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);\n        if (sar.num) {\n            print_q(\"sample_aspect_ratio\", sar, ':');\n        } else {\n            print_str_opt(\"sample_aspect_ratio\", \"N/A\");\n        }\n        print_fmt(\"pict_type\",              \"%c\", av_get_picture_type_char(frame->pict_type));\n        print_int(\"coded_picture_number\",   frame->coded_picture_number);\n        print_int(\"display_picture_number\", frame->display_picture_number);\n        print_int(\"interlaced_frame\",       frame->interlaced_frame);\n        print_int(\"top_field_first\",        frame->top_field_first);\n        print_int(\"repeat_pict\",            frame->repeat_pict);\n\n        print_color_range(w, frame->color_range);\n        print_color_space(w, frame->colorspace);\n        print_primaries(w, frame->color_primaries);\n        print_color_trc(w, frame->color_trc);\n        print_chroma_location(w, frame->chroma_location);\n        break;\n\n    case AVMEDIA_TYPE_AUDIO:\n        s = av_get_sample_fmt_name(frame->format);\n        if (s) print_str    (\"sample_fmt\", s);\n        else   print_str_opt(\"sample_fmt\", \"unknown\");\n        print_int(\"nb_samples\",         frame->nb_samples);\n        print_int(\"channels\", frame->ch_layout.nb_channels);\n        if (frame->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {\n            av_channel_layout_describe(&frame->ch_layout, val_str, sizeof(val_str));\n            print_str    (\"channel_layout\", val_str);\n        } else\n            print_str_opt(\"channel_layout\", \"unknown\");\n        break;\n    }\n    if (do_show_frame_tags)\n        show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS);\n    if (do_show_log)\n        show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log);\n    if (frame->nb_side_data) {\n        writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);\n        for (i = 0; i < frame->nb_side_data; i++) {\n            AVFrameSideData *sd = frame->side_data[i];\n            const char *name;\n\n            writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);\n            name = av_frame_side_data_name(sd->type);\n            print_str(\"side_data_type\", name ? name : \"unknown\");\n            if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {\n                writer_print_integers(w, \"displaymatrix\", sd->data, 9, \" %11d\", 3, 4, 1);\n                print_int(\"rotation\", av_display_rotation_get((int32_t *)sd->data));\n            } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {\n                print_int(\"active_format\", *sd->data);\n            } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {\n                char tcbuf[AV_TIMECODE_STR_SIZE];\n                av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));\n                print_str(\"timecode\", tcbuf);\n            } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) {\n                uint32_t *tc = (uint32_t*)sd->data;\n                int m = FFMIN(tc[0],3);\n                writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST);\n                for (int j = 1; j <= m ; j++) {\n                    char tcbuf[AV_TIMECODE_STR_SIZE];\n                    av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0);\n                    writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE);\n                    print_str(\"value\", tcbuf);\n                    writer_print_section_footer(w);\n                }\n                writer_print_section_footer(w);\n            } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {\n                AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;\n\n                if (metadata->has_primaries) {\n                    print_q(\"red_x\", metadata->display_primaries[0][0], '/');\n                    print_q(\"red_y\", metadata->display_primaries[0][1], '/');\n                    print_q(\"green_x\", metadata->display_primaries[1][0], '/');\n                    print_q(\"green_y\", metadata->display_primaries[1][1], '/');\n                    print_q(\"blue_x\", metadata->display_primaries[2][0], '/');\n                    print_q(\"blue_y\", metadata->display_primaries[2][1], '/');\n\n                    print_q(\"white_point_x\", metadata->white_point[0], '/');\n                    print_q(\"white_point_y\", metadata->white_point[1], '/');\n                }\n\n                if (metadata->has_luminance) {\n                    print_q(\"min_luminance\", metadata->min_luminance, '/');\n                    print_q(\"max_luminance\", metadata->max_luminance, '/');\n                }\n            } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {\n                AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;\n                print_dynamic_hdr10_plus(w, metadata);\n            } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {\n                AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;\n                print_int(\"max_content\", metadata->MaxCLL);\n                print_int(\"max_average\", metadata->MaxFALL);\n            } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {\n                const AVDictionaryEntry *tag = av_dict_get(sd->metadata, \"name\", NULL, AV_DICT_MATCH_CASE);\n                if (tag)\n                    print_str(tag->key, tag->value);\n                print_int(\"size\", sd->size);\n            } else if (sd->type == AV_FRAME_DATA_DOVI_METADATA) {\n                print_dovi_metadata(w, (const AVDOVIMetadata *)sd->data);\n            } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_VIVID) {\n                AVDynamicHDRVivid *metadata = (AVDynamicHDRVivid *)sd->data;\n                print_dynamic_hdr_vivid(w, metadata);\n            }\n            writer_print_section_footer(w);\n        }\n        writer_print_section_footer(w);\n    }\n\n    writer_print_section_footer(w);\n\n    av_bprint_finalize(&pbuf, NULL);\n    fflush(stdout);\n}\n\nstatic av_always_inline int process_frame(WriterContext *w,\n                                          InputFile *ifile,\n                                          AVFrame *frame, AVPacket *pkt,\n                                          int *packet_new)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx;\n    AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar;\n    AVSubtitle sub;\n    int ret = 0, got_frame = 0;\n\n    clear_log(1);\n    if (dec_ctx) {\n        switch (par->codec_type) {\n        case AVMEDIA_TYPE_VIDEO:\n        case AVMEDIA_TYPE_AUDIO:\n            if (*packet_new) {\n                ret = avcodec_send_packet(dec_ctx, pkt);\n                if (ret == AVERROR(EAGAIN)) {\n                    ret = 0;\n                } else if (ret >= 0 || ret == AVERROR_EOF) {\n                    ret = 0;\n                    *packet_new = 0;\n                }\n            }\n            if (ret >= 0) {\n                ret = avcodec_receive_frame(dec_ctx, frame);\n                if (ret >= 0) {\n                    got_frame = 1;\n                } else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {\n                    ret = 0;\n                }\n            }\n            break;\n\n        case AVMEDIA_TYPE_SUBTITLE:\n            if (*packet_new)\n                ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);\n            *packet_new = 0;\n            break;\n        default:\n            *packet_new = 0;\n        }\n    } else {\n        *packet_new = 0;\n    }\n\n    if (ret < 0)\n        return ret;\n    if (got_frame) {\n        int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE);\n        nb_streams_frames[pkt->stream_index]++;\n        if (do_show_frames)\n            if (is_sub)\n                show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx);\n            else\n                show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx);\n        if (is_sub)\n            avsubtitle_free(&sub);\n    }\n    return got_frame || *packet_new;\n}\n\nstatic void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)\n{\n    av_log(log_ctx, log_level, \"id:%d\", interval->id);\n\n    if (interval->has_start) {\n        av_log(log_ctx, log_level, \" start:%s%s\", interval->start_is_offset ? \"+\" : \"\",\n               av_ts2timestr(interval->start, &AV_TIME_BASE_Q));\n    } else {\n        av_log(log_ctx, log_level, \" start:N/A\");\n    }\n\n    if (interval->has_end) {\n        av_log(log_ctx, log_level, \" end:%s\", interval->end_is_offset ? \"+\" : \"\");\n        if (interval->duration_frames)\n            av_log(log_ctx, log_level, \"#%\"PRId64, interval->end);\n        else\n            av_log(log_ctx, log_level, \"%s\", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));\n    } else {\n        av_log(log_ctx, log_level, \" end:N/A\");\n    }\n\n    av_log(log_ctx, log_level, \"\\n\");\n}\n\nstatic int read_interval_packets(WriterContext *w, InputFile *ifile,\n                                 const ReadInterval *interval, int64_t *cur_ts)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    AVPacket *pkt = NULL;\n    AVFrame *frame = NULL;\n    int ret = 0, i = 0, frame_count = 0;\n    int64_t start = -INT64_MAX, end = interval->end;\n    int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;\n\n    av_log(NULL, AV_LOG_VERBOSE, \"Processing read interval \");\n    log_read_interval(interval, NULL, AV_LOG_VERBOSE);\n\n    if (interval->has_start) {\n        int64_t target;\n        if (interval->start_is_offset) {\n            if (*cur_ts == AV_NOPTS_VALUE) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Could not seek to relative position since current \"\n                       \"timestamp is not defined\\n\");\n                ret = AVERROR(EINVAL);\n                goto end;\n            }\n            target = *cur_ts + interval->start;\n        } else {\n            target = interval->start;\n        }\n\n        av_log(NULL, AV_LOG_VERBOSE, \"Seeking to read interval start point %s\\n\",\n               av_ts2timestr(target, &AV_TIME_BASE_Q));\n        if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Could not seek to position %\"PRId64\": %s\\n\",\n                   interval->start, av_err2str(ret));\n            goto end;\n        }\n    }\n\n    frame = av_frame_alloc();\n    if (!frame) {\n        ret = AVERROR(ENOMEM);\n        goto end;\n    }\n    pkt = av_packet_alloc();\n    if (!pkt) {\n        ret = AVERROR(ENOMEM);\n        goto end;\n    }\n    while (!av_read_frame(fmt_ctx, pkt)) {\n        if (fmt_ctx->nb_streams > nb_streams) {\n            REALLOCZ_ARRAY_STREAM(nb_streams_frames,  nb_streams, fmt_ctx->nb_streams);\n            REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);\n            REALLOCZ_ARRAY_STREAM(selected_streams,   nb_streams, fmt_ctx->nb_streams);\n            nb_streams = fmt_ctx->nb_streams;\n        }\n        if (selected_streams[pkt->stream_index]) {\n            AVRational tb = ifile->streams[pkt->stream_index].st->time_base;\n\n            if (pkt->pts != AV_NOPTS_VALUE)\n                *cur_ts = av_rescale_q(pkt->pts, tb, AV_TIME_BASE_Q);\n\n            if (!has_start && *cur_ts != AV_NOPTS_VALUE) {\n                start = *cur_ts;\n                has_start = 1;\n            }\n\n            if (has_start && !has_end && interval->end_is_offset) {\n                end = start + interval->end;\n                has_end = 1;\n            }\n\n            if (interval->end_is_offset && interval->duration_frames) {\n                if (frame_count >= interval->end)\n                    break;\n            } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {\n                break;\n            }\n\n            frame_count++;\n            if (do_read_packets) {\n                if (do_show_packets)\n                    show_packet(w, ifile, pkt, i++);\n                nb_streams_packets[pkt->stream_index]++;\n            }\n            if (do_read_frames) {\n                int packet_new = 1;\n                while (process_frame(w, ifile, frame, pkt, &packet_new) > 0);\n            }\n        }\n        av_packet_unref(pkt);\n    }\n    av_packet_unref(pkt);\n    //Flush remaining frames that are cached in the decoder\n    for (i = 0; i < fmt_ctx->nb_streams; i++) {\n        pkt->stream_index = i;\n        if (do_read_frames) {\n            while (process_frame(w, ifile, frame, pkt, &(int){1}) > 0);\n            if (ifile->streams[i].dec_ctx)\n                avcodec_flush_buffers(ifile->streams[i].dec_ctx);\n        }\n    }\n\nend:\n    av_frame_free(&frame);\n    av_packet_free(&pkt);\n    if (ret < 0) {\n        av_log(NULL, AV_LOG_ERROR, \"Could not read packets in interval \");\n        log_read_interval(interval, NULL, AV_LOG_ERROR);\n    }\n    return ret;\n}\n\nstatic int read_packets(WriterContext *w, InputFile *ifile)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    int i, ret = 0;\n    int64_t cur_ts = fmt_ctx->start_time;\n\n    if (read_intervals_nb == 0) {\n        ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };\n        ret = read_interval_packets(w, ifile, &interval, &cur_ts);\n    } else {\n        for (i = 0; i < read_intervals_nb; i++) {\n            ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts);\n            if (ret < 0)\n                break;\n        }\n    }\n\n    return ret;\n}\n\nstatic int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program)\n{\n    AVStream *stream = ist->st;\n    AVCodecParameters *par;\n    AVCodecContext *dec_ctx;\n    char val_str[128];\n    const char *s;\n    AVRational sar, dar;\n    AVBPrint pbuf;\n    const AVCodecDescriptor *cd;\n    int ret = 0;\n    const char *profile = NULL;\n\n    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);\n\n    print_int(\"index\", stream->index);\n\n    par     = stream->codecpar;\n    dec_ctx = ist->dec_ctx;\n    if (cd = avcodec_descriptor_get(par->codec_id)) {\n        print_str(\"codec_name\", cd->name);\n        if (!do_bitexact) {\n            print_str(\"codec_long_name\",\n                      cd->long_name ? cd->long_name : \"unknown\");\n        }\n    } else {\n        print_str_opt(\"codec_name\", \"unknown\");\n        if (!do_bitexact) {\n            print_str_opt(\"codec_long_name\", \"unknown\");\n        }\n    }\n\n    if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile)))\n        print_str(\"profile\", profile);\n    else {\n        if (par->profile != FF_PROFILE_UNKNOWN) {\n            char profile_num[12];\n            snprintf(profile_num, sizeof(profile_num), \"%d\", par->profile);\n            print_str(\"profile\", profile_num);\n        } else\n            print_str_opt(\"profile\", \"unknown\");\n    }\n\n    s = av_get_media_type_string(par->codec_type);\n    if (s) print_str    (\"codec_type\", s);\n    else   print_str_opt(\"codec_type\", \"unknown\");\n\n    /* print AVI/FourCC tag */\n    print_str(\"codec_tag_string\",    av_fourcc2str(par->codec_tag));\n    print_fmt(\"codec_tag\", \"0x%04\"PRIx32, par->codec_tag);\n\n    switch (par->codec_type) {\n    case AVMEDIA_TYPE_VIDEO:\n        print_int(\"width\",        par->width);\n        print_int(\"height\",       par->height);\n        if (dec_ctx) {\n            print_int(\"coded_width\",  dec_ctx->coded_width);\n            print_int(\"coded_height\", dec_ctx->coded_height);\n            print_int(\"closed_captions\", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS));\n            print_int(\"film_grain\", !!(dec_ctx->properties & FF_CODEC_PROPERTY_FILM_GRAIN));\n        }\n        print_int(\"has_b_frames\", par->video_delay);\n        sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);\n        if (sar.num) {\n            print_q(\"sample_aspect_ratio\", sar, ':');\n            av_reduce(&dar.num, &dar.den,\n                      par->width  * sar.num,\n                      par->height * sar.den,\n                      1024*1024);\n            print_q(\"display_aspect_ratio\", dar, ':');\n        } else {\n            print_str_opt(\"sample_aspect_ratio\", \"N/A\");\n            print_str_opt(\"display_aspect_ratio\", \"N/A\");\n        }\n        s = av_get_pix_fmt_name(par->format);\n        if (s) print_str    (\"pix_fmt\", s);\n        else   print_str_opt(\"pix_fmt\", \"unknown\");\n        print_int(\"level\",   par->level);\n\n        print_color_range(w, par->color_range);\n        print_color_space(w, par->color_space);\n        print_color_trc(w, par->color_trc);\n        print_primaries(w, par->color_primaries);\n        print_chroma_location(w, par->chroma_location);\n\n        if (par->field_order == AV_FIELD_PROGRESSIVE)\n            print_str(\"field_order\", \"progressive\");\n        else if (par->field_order == AV_FIELD_TT)\n            print_str(\"field_order\", \"tt\");\n        else if (par->field_order == AV_FIELD_BB)\n            print_str(\"field_order\", \"bb\");\n        else if (par->field_order == AV_FIELD_TB)\n            print_str(\"field_order\", \"tb\");\n        else if (par->field_order == AV_FIELD_BT)\n            print_str(\"field_order\", \"bt\");\n        else\n            print_str_opt(\"field_order\", \"unknown\");\n\n        if (dec_ctx)\n            print_int(\"refs\", dec_ctx->refs);\n        break;\n\n    case AVMEDIA_TYPE_AUDIO:\n        s = av_get_sample_fmt_name(par->format);\n        if (s) print_str    (\"sample_fmt\", s);\n        else   print_str_opt(\"sample_fmt\", \"unknown\");\n        print_val(\"sample_rate\",     par->sample_rate, unit_hertz_str);\n        print_int(\"channels\",        par->ch_layout.nb_channels);\n\n        if (par->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {\n            av_channel_layout_describe(&par->ch_layout, val_str, sizeof(val_str));\n            print_str    (\"channel_layout\", val_str);\n        } else {\n            print_str_opt(\"channel_layout\", \"unknown\");\n        }\n\n        print_int(\"bits_per_sample\", av_get_bits_per_sample(par->codec_id));\n        break;\n\n    case AVMEDIA_TYPE_SUBTITLE:\n        if (par->width)\n            print_int(\"width\",       par->width);\n        else\n            print_str_opt(\"width\",   \"N/A\");\n        if (par->height)\n            print_int(\"height\",      par->height);\n        else\n            print_str_opt(\"height\",  \"N/A\");\n        break;\n    }\n\n    if (dec_ctx && dec_ctx->codec->priv_class && show_private_data) {\n        const AVOption *opt = NULL;\n        while (opt = av_opt_next(dec_ctx->priv_data,opt)) {\n            uint8_t *str;\n            if (!(opt->flags & AV_OPT_FLAG_EXPORT)) continue;\n            if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {\n                print_str(opt->name, str);\n                av_free(str);\n            }\n        }\n    }\n\n    if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt    (\"id\", \"0x%x\", stream->id);\n    else                                          print_str_opt(\"id\", \"N/A\");\n    print_q(\"r_frame_rate\",   stream->r_frame_rate,   '/');\n    print_q(\"avg_frame_rate\", stream->avg_frame_rate, '/');\n    print_q(\"time_base\",      stream->time_base,      '/');\n    print_ts  (\"start_pts\",   stream->start_time);\n    print_time(\"start_time\",  stream->start_time, &stream->time_base);\n    print_ts  (\"duration_ts\", stream->duration);\n    print_time(\"duration\",    stream->duration, &stream->time_base);\n    if (par->bit_rate > 0)     print_val    (\"bit_rate\", par->bit_rate, unit_bit_per_second_str);\n    else                       print_str_opt(\"bit_rate\", \"N/A\");\n    if (dec_ctx && dec_ctx->rc_max_rate > 0)\n        print_val (\"max_bit_rate\", dec_ctx->rc_max_rate, unit_bit_per_second_str);\n    else\n        print_str_opt(\"max_bit_rate\", \"N/A\");\n    if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt(\"bits_per_raw_sample\", \"%d\", dec_ctx->bits_per_raw_sample);\n    else                                             print_str_opt(\"bits_per_raw_sample\", \"N/A\");\n    if (stream->nb_frames) print_fmt    (\"nb_frames\", \"%\"PRId64, stream->nb_frames);\n    else                   print_str_opt(\"nb_frames\", \"N/A\");\n    if (nb_streams_frames[stream_idx])  print_fmt    (\"nb_read_frames\", \"%\"PRIu64, nb_streams_frames[stream_idx]);\n    else                                print_str_opt(\"nb_read_frames\", \"N/A\");\n    if (nb_streams_packets[stream_idx]) print_fmt    (\"nb_read_packets\", \"%\"PRIu64, nb_streams_packets[stream_idx]);\n    else                                print_str_opt(\"nb_read_packets\", \"N/A\");\n    if (do_show_data)\n        writer_print_data(w, \"extradata\", par->extradata,\n                                          par->extradata_size);\n\n    if (par->extradata_size > 0) {\n        print_int(\"extradata_size\", par->extradata_size);\n        writer_print_data_hash(w, \"extradata_hash\", par->extradata,\n                                                    par->extradata_size);\n    }\n\n    /* Print disposition information */\n#define PRINT_DISPOSITION(flagname, name) do {                                \\\n        print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \\\n    } while (0)\n\n    if (do_show_stream_disposition) {\n        writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);\n        PRINT_DISPOSITION(DEFAULT,          \"default\");\n        PRINT_DISPOSITION(DUB,              \"dub\");\n        PRINT_DISPOSITION(ORIGINAL,         \"original\");\n        PRINT_DISPOSITION(COMMENT,          \"comment\");\n        PRINT_DISPOSITION(LYRICS,           \"lyrics\");\n        PRINT_DISPOSITION(KARAOKE,          \"karaoke\");\n        PRINT_DISPOSITION(FORCED,           \"forced\");\n        PRINT_DISPOSITION(HEARING_IMPAIRED, \"hearing_impaired\");\n        PRINT_DISPOSITION(VISUAL_IMPAIRED,  \"visual_impaired\");\n        PRINT_DISPOSITION(CLEAN_EFFECTS,    \"clean_effects\");\n        PRINT_DISPOSITION(ATTACHED_PIC,     \"attached_pic\");\n        PRINT_DISPOSITION(TIMED_THUMBNAILS, \"timed_thumbnails\");\n        PRINT_DISPOSITION(CAPTIONS,         \"captions\");\n        PRINT_DISPOSITION(DESCRIPTIONS,     \"descriptions\");\n        PRINT_DISPOSITION(METADATA,         \"metadata\");\n        PRINT_DISPOSITION(DEPENDENT,        \"dependent\");\n        PRINT_DISPOSITION(STILL_IMAGE,      \"still_image\");\n        writer_print_section_footer(w);\n    }\n\n    if (do_show_stream_tags)\n        ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);\n\n    if (stream->nb_side_data) {\n        print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data,\n                            SECTION_ID_STREAM_SIDE_DATA_LIST,\n                            SECTION_ID_STREAM_SIDE_DATA);\n    }\n\n    writer_print_section_footer(w);\n    av_bprint_finalize(&pbuf, NULL);\n    fflush(stdout);\n\n    return ret;\n}\n\nstatic int show_streams(WriterContext *w, InputFile *ifile)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    int i, ret = 0;\n\n    writer_print_section_header(w, SECTION_ID_STREAMS);\n    for (i = 0; i < ifile->nb_streams; i++)\n        if (selected_streams[i]) {\n            ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0);\n            if (ret < 0)\n                break;\n        }\n    writer_print_section_footer(w);\n\n    return ret;\n}\n\nstatic int show_program(WriterContext *w, InputFile *ifile, AVProgram *program)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    int i, ret = 0;\n\n    writer_print_section_header(w, SECTION_ID_PROGRAM);\n    print_int(\"program_id\", program->id);\n    print_int(\"program_num\", program->program_num);\n    print_int(\"nb_streams\", program->nb_stream_indexes);\n    print_int(\"pmt_pid\", program->pmt_pid);\n    print_int(\"pcr_pid\", program->pcr_pid);\n    if (do_show_program_tags)\n        ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);\n    if (ret < 0)\n        goto end;\n\n    writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);\n    for (i = 0; i < program->nb_stream_indexes; i++) {\n        if (selected_streams[program->stream_index[i]]) {\n            ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1);\n            if (ret < 0)\n                break;\n        }\n    }\n    writer_print_section_footer(w);\n\nend:\n    writer_print_section_footer(w);\n    return ret;\n}\n\nstatic int show_programs(WriterContext *w, InputFile *ifile)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    int i, ret = 0;\n\n    writer_print_section_header(w, SECTION_ID_PROGRAMS);\n    for (i = 0; i < fmt_ctx->nb_programs; i++) {\n        AVProgram *program = fmt_ctx->programs[i];\n        if (!program)\n            continue;\n        ret = show_program(w, ifile, program);\n        if (ret < 0)\n            break;\n    }\n    writer_print_section_footer(w);\n    return ret;\n}\n\nstatic int show_chapters(WriterContext *w, InputFile *ifile)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    int i, ret = 0;\n\n    writer_print_section_header(w, SECTION_ID_CHAPTERS);\n    for (i = 0; i < fmt_ctx->nb_chapters; i++) {\n        AVChapter *chapter = fmt_ctx->chapters[i];\n\n        writer_print_section_header(w, SECTION_ID_CHAPTER);\n        print_int(\"id\", chapter->id);\n        print_q  (\"time_base\", chapter->time_base, '/');\n        print_int(\"start\", chapter->start);\n        print_time(\"start_time\", chapter->start, &chapter->time_base);\n        print_int(\"end\", chapter->end);\n        print_time(\"end_time\", chapter->end, &chapter->time_base);\n        if (do_show_chapter_tags)\n            ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);\n        writer_print_section_footer(w);\n    }\n    writer_print_section_footer(w);\n\n    return ret;\n}\n\nstatic int show_format(WriterContext *w, InputFile *ifile)\n{\n    AVFormatContext *fmt_ctx = ifile->fmt_ctx;\n    char val_str[128];\n    int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;\n    int ret = 0;\n\n    writer_print_section_header(w, SECTION_ID_FORMAT);\n    print_str_validate(\"filename\", fmt_ctx->url);\n    print_int(\"nb_streams\",       fmt_ctx->nb_streams);\n    print_int(\"nb_programs\",      fmt_ctx->nb_programs);\n    print_str(\"format_name\",      fmt_ctx->iformat->name);\n    if (!do_bitexact) {\n        if (fmt_ctx->iformat->long_name) print_str    (\"format_long_name\", fmt_ctx->iformat->long_name);\n        else                             print_str_opt(\"format_long_name\", \"unknown\");\n    }\n    print_time(\"start_time\",      fmt_ctx->start_time, &AV_TIME_BASE_Q);\n    print_time(\"duration\",        fmt_ctx->duration,   &AV_TIME_BASE_Q);\n    if (size >= 0) print_val    (\"size\", size, unit_byte_str);\n    else           print_str_opt(\"size\", \"N/A\");\n    if (fmt_ctx->bit_rate > 0) print_val    (\"bit_rate\", fmt_ctx->bit_rate, unit_bit_per_second_str);\n    else                       print_str_opt(\"bit_rate\", \"N/A\");\n    print_int(\"probe_score\", fmt_ctx->probe_score);\n    if (do_show_format_tags)\n        ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);\n\n    writer_print_section_footer(w);\n    fflush(stdout);\n    return ret;\n}\n\nstatic void show_error(WriterContext *w, int err)\n{\n    char errbuf[128];\n    const char *errbuf_ptr = errbuf;\n\n    if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)\n        errbuf_ptr = strerror(AVUNERROR(err));\n\n    writer_print_section_header(w, SECTION_ID_ERROR);\n    print_int(\"code\", err);\n    print_str(\"string\", errbuf_ptr);\n    writer_print_section_footer(w);\n}\n\nstatic int open_input_file(InputFile *ifile, const char *filename,\n                           const char *print_filename)\n{\n    int err, i;\n    AVFormatContext *fmt_ctx = NULL;\n    const AVDictionaryEntry *t = NULL;\n    int scan_all_pmts_set = 0;\n\n    fmt_ctx = avformat_alloc_context();\n    if (!fmt_ctx) {\n        print_error(filename, AVERROR(ENOMEM));\n        exit_program(1);\n    }\n\n    if (!av_dict_get(format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE)) {\n        av_dict_set(&format_opts, \"scan_all_pmts\", \"1\", AV_DICT_DONT_OVERWRITE);\n        scan_all_pmts_set = 1;\n    }\n    if ((err = avformat_open_input(&fmt_ctx, filename,\n                                   iformat, &format_opts)) < 0) {\n        print_error(filename, err);\n        return err;\n    }\n    if (print_filename) {\n        av_freep(&fmt_ctx->url);\n        fmt_ctx->url = av_strdup(print_filename);\n    }\n    ifile->fmt_ctx = fmt_ctx;\n    if (scan_all_pmts_set)\n        av_dict_set(&format_opts, \"scan_all_pmts\", NULL, AV_DICT_MATCH_CASE);\n    while ((t = av_dict_get(format_opts, \"\", t, AV_DICT_IGNORE_SUFFIX)))\n        av_log(NULL, AV_LOG_WARNING, \"Option %s skipped - not known to demuxer.\\n\", t->key);\n\n    if (find_stream_info) {\n        AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);\n        int orig_nb_streams = fmt_ctx->nb_streams;\n\n        err = avformat_find_stream_info(fmt_ctx, opts);\n\n        for (i = 0; i < orig_nb_streams; i++)\n            av_dict_free(&opts[i]);\n        av_freep(&opts);\n\n        if (err < 0) {\n            print_error(filename, err);\n            return err;\n        }\n    }\n\n    av_dump_format(fmt_ctx, 0, filename, 0);\n\n    ifile->streams = av_calloc(fmt_ctx->nb_streams, sizeof(*ifile->streams));\n    if (!ifile->streams)\n        exit(1);\n    ifile->nb_streams = fmt_ctx->nb_streams;\n\n    /* bind a decoder to each input stream */\n    for (i = 0; i < fmt_ctx->nb_streams; i++) {\n        InputStream *ist = &ifile->streams[i];\n        AVStream *stream = fmt_ctx->streams[i];\n        const AVCodec *codec;\n\n        ist->st = stream;\n\n        if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) {\n            av_log(NULL, AV_LOG_WARNING,\n                   \"Failed to probe codec for input stream %d\\n\",\n                    stream->index);\n            continue;\n        }\n\n        codec = avcodec_find_decoder(stream->codecpar->codec_id);\n        if (!codec) {\n            av_log(NULL, AV_LOG_WARNING,\n                    \"Unsupported codec with id %d for input stream %d\\n\",\n                    stream->codecpar->codec_id, stream->index);\n            continue;\n        }\n        {\n            AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id,\n                                                   fmt_ctx, stream, codec);\n\n            ist->dec_ctx = avcodec_alloc_context3(codec);\n            if (!ist->dec_ctx)\n                exit(1);\n\n            err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar);\n            if (err < 0)\n                exit(1);\n\n            if (do_show_log) {\n                // For loging it is needed to disable at least frame threads as otherwise\n                // the log information would need to be reordered and matches up to contexts and frames\n                // That is in fact possible but not trivial\n                av_dict_set(&codec_opts, \"threads\", \"1\", 0);\n            }\n\n            ist->dec_ctx->pkt_timebase = stream->time_base;\n\n            if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) {\n                av_log(NULL, AV_LOG_WARNING, \"Could not open codec for input stream %d\\n\",\n                       stream->index);\n                exit(1);\n            }\n\n            if ((t = av_dict_get(opts, \"\", NULL, AV_DICT_IGNORE_SUFFIX))) {\n                av_log(NULL, AV_LOG_ERROR, \"Option %s for input stream %d not found\\n\",\n                       t->key, stream->index);\n                return AVERROR_OPTION_NOT_FOUND;\n            }\n        }\n    }\n\n    ifile->fmt_ctx = fmt_ctx;\n    return 0;\n}\n\nstatic void close_input_file(InputFile *ifile)\n{\n    int i;\n\n    /* close decoder for each stream */\n    for (i = 0; i < ifile->nb_streams; i++)\n        avcodec_free_context(&ifile->streams[i].dec_ctx);\n\n    av_freep(&ifile->streams);\n    ifile->nb_streams = 0;\n\n    avformat_close_input(&ifile->fmt_ctx);\n}\n\nstatic int probe_file(WriterContext *wctx, const char *filename,\n                      const char *print_filename)\n{\n    InputFile ifile = { 0 };\n    int ret, i;\n    int section_id;\n\n    do_read_frames = do_show_frames || do_count_frames;\n    do_read_packets = do_show_packets || do_count_packets;\n\n    ret = open_input_file(&ifile, filename, print_filename);\n    if (ret < 0)\n        goto end;\n\n#define CHECK_END if (ret < 0) goto end\n\n    nb_streams = ifile.fmt_ctx->nb_streams;\n    REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams);\n    REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams);\n    REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams);\n\n    for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {\n        if (stream_specifier) {\n            ret = avformat_match_stream_specifier(ifile.fmt_ctx,\n                                                  ifile.fmt_ctx->streams[i],\n                                                  stream_specifier);\n            CHECK_END;\n            else\n                selected_streams[i] = ret;\n            ret = 0;\n        } else {\n            selected_streams[i] = 1;\n        }\n        if (!selected_streams[i])\n            ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL;\n    }\n\n    if (do_read_frames || do_read_packets) {\n        if (do_show_frames && do_show_packets &&\n            wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)\n            section_id = SECTION_ID_PACKETS_AND_FRAMES;\n        else if (do_show_packets && !do_show_frames)\n            section_id = SECTION_ID_PACKETS;\n        else // (!do_show_packets && do_show_frames)\n            section_id = SECTION_ID_FRAMES;\n        if (do_show_frames || do_show_packets)\n            writer_print_section_header(wctx, section_id);\n        ret = read_packets(wctx, &ifile);\n        if (do_show_frames || do_show_packets)\n            writer_print_section_footer(wctx);\n        CHECK_END;\n    }\n\n    if (do_show_programs) {\n        ret = show_programs(wctx, &ifile);\n        CHECK_END;\n    }\n\n    if (do_show_streams) {\n        ret = show_streams(wctx, &ifile);\n        CHECK_END;\n    }\n    if (do_show_chapters) {\n        ret = show_chapters(wctx, &ifile);\n        CHECK_END;\n    }\n    if (do_show_format) {\n        ret = show_format(wctx, &ifile);\n        CHECK_END;\n    }\n\nend:\n    if (ifile.fmt_ctx)\n        close_input_file(&ifile);\n    av_freep(&nb_streams_frames);\n    av_freep(&nb_streams_packets);\n    av_freep(&selected_streams);\n\n    return ret;\n}\n\nstatic void show_usage(void)\n{\n    av_log(NULL, AV_LOG_INFO, \"Simple multimedia streams analyzer\\n\");\n    av_log(NULL, AV_LOG_INFO, \"usage: %s [OPTIONS] INPUT_FILE\\n\", program_name_ffprobe);\n    av_log(NULL, AV_LOG_INFO, \"\\n\");\n}\n\nstatic void ffprobe_show_program_version(WriterContext *w)\n{\n    AVBPrint pbuf;\n    av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);\n\n    writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);\n    print_str(\"version\", FFMPEG_VERSION);\n    print_fmt(\"copyright\", \"Copyright (c) %d-%d the FFmpeg developers\",\n              program_birth_year_ffprobe, CONFIG_THIS_YEAR);\n    print_str(\"compiler_ident\", CC_IDENT);\n    print_str(\"configuration\", FFMPEG_CONFIGURATION);\n    writer_print_section_footer(w);\n\n    av_bprint_finalize(&pbuf, NULL);\n}\n\n#define SHOW_LIB_VERSION(libname, LIBNAME)                              \\\n    do {                                                                \\\n        if (CONFIG_##LIBNAME) {                                         \\\n            unsigned int version = libname##_version();                 \\\n            writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \\\n            print_str(\"name\",    \"lib\" #libname);                       \\\n            print_int(\"major\",   LIB##LIBNAME##_VERSION_MAJOR);         \\\n            print_int(\"minor\",   LIB##LIBNAME##_VERSION_MINOR);         \\\n            print_int(\"micro\",   LIB##LIBNAME##_VERSION_MICRO);         \\\n            print_int(\"version\", version);                              \\\n            print_str(\"ident\",   LIB##LIBNAME##_IDENT);                 \\\n            writer_print_section_footer(w);                             \\\n        }                                                               \\\n    } while (0)\n\nstatic void ffprobe_show_library_versions(WriterContext *w)\n{\n    writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);\n    SHOW_LIB_VERSION(avutil,     AVUTIL);\n    SHOW_LIB_VERSION(avcodec,    AVCODEC);\n    SHOW_LIB_VERSION(avformat,   AVFORMAT);\n    SHOW_LIB_VERSION(avdevice,   AVDEVICE);\n    SHOW_LIB_VERSION(avfilter,   AVFILTER);\n    SHOW_LIB_VERSION(swscale,    SWSCALE);\n    SHOW_LIB_VERSION(swresample, SWRESAMPLE);\n    SHOW_LIB_VERSION(postproc,   POSTPROC);\n    writer_print_section_footer(w);\n}\n\n#define PRINT_PIX_FMT_FLAG(flagname, name)                                \\\n    do {                                                                  \\\n        print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \\\n    } while (0)\n\nstatic void ffprobe_show_pixel_formats(WriterContext *w)\n{\n    const AVPixFmtDescriptor *pixdesc = NULL;\n    int i, n;\n\n    writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);\n    while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {\n        writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);\n        print_str(\"name\", pixdesc->name);\n        print_int(\"nb_components\", pixdesc->nb_components);\n        if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {\n            print_int    (\"log2_chroma_w\", pixdesc->log2_chroma_w);\n            print_int    (\"log2_chroma_h\", pixdesc->log2_chroma_h);\n        } else {\n            print_str_opt(\"log2_chroma_w\", \"N/A\");\n            print_str_opt(\"log2_chroma_h\", \"N/A\");\n        }\n        n = av_get_bits_per_pixel(pixdesc);\n        if (n) print_int    (\"bits_per_pixel\", n);\n        else   print_str_opt(\"bits_per_pixel\", \"N/A\");\n        if (do_show_pixel_format_flags) {\n            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);\n            PRINT_PIX_FMT_FLAG(BE,        \"big_endian\");\n            PRINT_PIX_FMT_FLAG(PAL,       \"palette\");\n            PRINT_PIX_FMT_FLAG(BITSTREAM, \"bitstream\");\n            PRINT_PIX_FMT_FLAG(HWACCEL,   \"hwaccel\");\n            PRINT_PIX_FMT_FLAG(PLANAR,    \"planar\");\n            PRINT_PIX_FMT_FLAG(RGB,       \"rgb\");\n            PRINT_PIX_FMT_FLAG(ALPHA,     \"alpha\");\n            writer_print_section_footer(w);\n        }\n        if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {\n            writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);\n            for (i = 0; i < pixdesc->nb_components; i++) {\n                writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);\n                print_int(\"index\", i + 1);\n                print_int(\"bit_depth\", pixdesc->comp[i].depth);\n                writer_print_section_footer(w);\n            }\n            writer_print_section_footer(w);\n        }\n        writer_print_section_footer(w);\n    }\n    writer_print_section_footer(w);\n}\n\nstatic int opt_show_optional_fields(void *optctx, const char *opt, const char *arg)\n{\n    if      (!av_strcasecmp(arg, \"always\")) show_optional_fields = SHOW_OPTIONAL_FIELDS_ALWAYS;\n    else if (!av_strcasecmp(arg, \"never\"))  show_optional_fields = SHOW_OPTIONAL_FIELDS_NEVER;\n    else if (!av_strcasecmp(arg, \"auto\"))   show_optional_fields = SHOW_OPTIONAL_FIELDS_AUTO;\n\n    if (show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO && av_strcasecmp(arg, \"auto\"))\n        show_optional_fields = parse_number_or_die(\"show_optional_fields\", arg, OPT_INT, SHOW_OPTIONAL_FIELDS_AUTO, SHOW_OPTIONAL_FIELDS_ALWAYS);\n    return 0;\n}\n\nstatic int opt_format(void *optctx, const char *opt, const char *arg)\n{\n    iformat = av_find_input_format(arg);\n    if (!iformat) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown input format: %s\\n\", arg);\n        return AVERROR(EINVAL);\n    }\n    return 0;\n}\n\nstatic inline void mark_section_show_entries(SectionID section_id,\n                                             int show_all_entries, AVDictionary *entries)\n{\n    struct section *section = &sections[section_id];\n\n    section->show_all_entries = show_all_entries;\n    if (show_all_entries) {\n        SectionID *id;\n        for (id = section->children_ids; *id != -1; id++)\n            mark_section_show_entries(*id, show_all_entries, entries);\n    } else {\n        av_dict_copy(&section->entries_to_show, entries, 0);\n    }\n}\n\nstatic int match_section(const char *section_name,\n                         int show_all_entries, AVDictionary *entries)\n{\n    int i, ret = 0;\n\n    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {\n        const struct section *section = &sections[i];\n        if (!strcmp(section_name, section->name) ||\n            (section->unique_name && !strcmp(section_name, section->unique_name))) {\n            av_log(NULL, AV_LOG_DEBUG,\n                   \"'%s' matches section with unique name '%s'\\n\", section_name,\n                   (char *)av_x_if_null(section->unique_name, section->name));\n            ret++;\n            mark_section_show_entries(section->id, show_all_entries, entries);\n        }\n    }\n    return ret;\n}\n\nstatic int opt_show_entries(void *optctx, const char *opt, const char *arg)\n{\n    const char *p = arg;\n    int ret = 0;\n\n    while (*p) {\n        AVDictionary *entries = NULL;\n        char *section_name = av_get_token(&p, \"=:\");\n        int show_all_entries = 0;\n\n        if (!section_name) {\n            av_log(NULL, AV_LOG_ERROR,\n                   \"Missing section name for option '%s'\\n\", opt);\n            return AVERROR(EINVAL);\n        }\n\n        if (*p == '=') {\n            p++;\n            while (*p && *p != ':') {\n                char *entry = av_get_token(&p, \",:\");\n                if (!entry)\n                    break;\n                av_log(NULL, AV_LOG_VERBOSE,\n                       \"Adding '%s' to the entries to show in section '%s'\\n\",\n                       entry, section_name);\n                av_dict_set(&entries, entry, \"\", AV_DICT_DONT_STRDUP_KEY);\n                if (*p == ',')\n                    p++;\n            }\n        } else {\n            show_all_entries = 1;\n        }\n\n        ret = match_section(section_name, show_all_entries, entries);\n        if (ret == 0) {\n            av_log(NULL, AV_LOG_ERROR, \"No match for section '%s'\\n\", section_name);\n            ret = AVERROR(EINVAL);\n        }\n        av_dict_free(&entries);\n        av_free(section_name);\n\n        if (ret <= 0)\n            break;\n        if (*p)\n            p++;\n    }\n\n    return ret;\n}\n\nstatic void opt_input_file(void *optctx, const char *arg)\n{\n    if (input_filename) {\n        av_log(NULL, AV_LOG_ERROR,\n                \"Argument '%s' provided as input filename, but '%s' was already specified.\\n\",\n                arg, input_filename);\n        exit_program(1);\n    }\n    if (!strcmp(arg, \"-\"))\n        arg = \"pipe:\";\n    input_filename = arg;\n}\n\nstatic int opt_input_file_i(void *optctx, const char *opt, const char *arg)\n{\n    opt_input_file(optctx, arg);\n    return 0;\n}\n\nstatic void opt_output_file(void *optctx, const char *arg)\n{\n    if (output_filename) {\n        av_log(NULL, AV_LOG_ERROR,\n                \"Argument '%s' provided as output filename, but '%s' was already specified.\\n\",\n                arg, output_filename);\n        exit_program(1);\n    }\n    if (!strcmp(arg, \"-\"))\n        arg = \"pipe:\";\n    output_filename = arg;\n}\n\nstatic int opt_output_file_o(void *optctx, const char *opt, const char *arg)\n{\n    opt_output_file(optctx, arg);\n    return 0;\n}\n\nstatic int opt_print_filename(void *optctx, const char *opt, const char *arg)\n{\n    print_input_filename = arg;\n    return 0;\n}\n\nvoid show_help_default_ffprobe(const char *opt, const char *arg)\n{\n    av_log_set_callback(log_callback_help);\n    show_usage();\n    show_help_options(options, \"Main options:\", 0, 0, 0);\n    printf(\"\\n\");\n\n    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);\n    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);\n}\n\n/**\n * Parse interval specification, according to the format:\n * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]\n * INTERVALS ::= INTERVAL[,INTERVALS]\n*/\nstatic int parse_read_interval(const char *interval_spec,\n                               ReadInterval *interval)\n{\n    int ret = 0;\n    char *next, *p, *spec = av_strdup(interval_spec);\n    if (!spec)\n        return AVERROR(ENOMEM);\n\n    if (!*spec) {\n        av_log(NULL, AV_LOG_ERROR, \"Invalid empty interval specification\\n\");\n        ret = AVERROR(EINVAL);\n        goto end;\n    }\n\n    p = spec;\n    next = strchr(spec, '%');\n    if (next)\n        *next++ = 0;\n\n    /* parse first part */\n    if (*p) {\n        interval->has_start = 1;\n\n        if (*p == '+') {\n            interval->start_is_offset = 1;\n            p++;\n        } else {\n            interval->start_is_offset = 0;\n        }\n\n        ret = av_parse_time(&interval->start, p, 1);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Invalid interval start specification '%s'\\n\", p);\n            goto end;\n        }\n    } else {\n        interval->has_start = 0;\n    }\n\n    /* parse second part */\n    p = next;\n    if (p && *p) {\n        int64_t us;\n        interval->has_end = 1;\n\n        if (*p == '+') {\n            interval->end_is_offset = 1;\n            p++;\n        } else {\n            interval->end_is_offset = 0;\n        }\n\n        if (interval->end_is_offset && *p == '#') {\n            long long int lli;\n            char *tail;\n            interval->duration_frames = 1;\n            p++;\n            lli = strtoll(p, &tail, 10);\n            if (*tail || lli < 0) {\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Invalid or negative value '%s' for duration number of frames\\n\", p);\n                goto end;\n            }\n            interval->end = lli;\n        } else {\n            interval->duration_frames = 0;\n            ret = av_parse_time(&us, p, 1);\n            if (ret < 0) {\n                av_log(NULL, AV_LOG_ERROR, \"Invalid interval end/duration specification '%s'\\n\", p);\n                goto end;\n            }\n            interval->end = us;\n        }\n    } else {\n        interval->has_end = 0;\n    }\n\nend:\n    av_free(spec);\n    return ret;\n}\n\nstatic int parse_read_intervals(const char *intervals_spec)\n{\n    int ret, n, i;\n    char *p, *spec = av_strdup(intervals_spec);\n    if (!spec)\n        return AVERROR(ENOMEM);\n\n    /* preparse specification, get number of intervals */\n    for (n = 0, p = spec; *p; p++)\n        if (*p == ',')\n            n++;\n    n++;\n\n    read_intervals = av_malloc_array(n, sizeof(*read_intervals));\n    if (!read_intervals) {\n        ret = AVERROR(ENOMEM);\n        goto end;\n    }\n    read_intervals_nb = n;\n\n    /* parse intervals */\n    p = spec;\n    for (i = 0; p; i++) {\n        char *next;\n\n        av_assert0(i < read_intervals_nb);\n        next = strchr(p, ',');\n        if (next)\n            *next++ = 0;\n\n        read_intervals[i].id = i;\n        ret = parse_read_interval(p, &read_intervals[i]);\n        if (ret < 0) {\n            av_log(NULL, AV_LOG_ERROR, \"Error parsing read interval #%d '%s'\\n\",\n                   i, p);\n            goto end;\n        }\n        av_log(NULL, AV_LOG_VERBOSE, \"Parsed log interval \");\n        log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);\n        p = next;\n    }\n    av_assert0(i == read_intervals_nb);\n\nend:\n    av_free(spec);\n    return ret;\n}\n\nstatic int opt_read_intervals(void *optctx, const char *opt, const char *arg)\n{\n    return parse_read_intervals(arg);\n}\n\nstatic int opt_pretty(void *optctx, const char *opt, const char *arg)\n{\n    show_value_unit              = 1;\n    use_value_prefix             = 1;\n    use_byte_value_binary_prefix = 1;\n    use_value_sexagesimal_format = 1;\n    return 0;\n}\n\nstatic void print_section(SectionID id, int level)\n{\n    const SectionID *pid;\n    const struct section *section = &sections[id];\n    printf(\"%c%c%c\",\n           section->flags & SECTION_FLAG_IS_WRAPPER           ? 'W' : '.',\n           section->flags & SECTION_FLAG_IS_ARRAY             ? 'A' : '.',\n           section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS  ? 'V' : '.');\n    printf(\"%*c  %s\", level * 4, ' ', section->name);\n    if (section->unique_name)\n        printf(\"/%s\", section->unique_name);\n    printf(\"\\n\");\n\n    for (pid = section->children_ids; *pid != -1; pid++)\n        print_section(*pid, level+1);\n}\n\nstatic int opt_sections(void *optctx, const char *opt, const char *arg)\n{\n    printf(\"Sections:\\n\"\n           \"W.. = Section is a wrapper (contains other sections, no local entries)\\n\"\n           \".A. = Section contains an array of elements of the same type\\n\"\n           \"..V = Section may contain a variable number of fields with variable keys\\n\"\n           \"FLAGS NAME/UNIQUE_NAME\\n\"\n           \"---\\n\");\n    print_section(SECTION_ID_ROOT, 0);\n    return 0;\n}\n\nstatic int opt_show_versions(void *optctx, const char *opt, const char *arg)\n{\n    mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);\n    mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);\n    return 0;\n}\n\n#define DEFINE_OPT_SHOW_SECTION(section, target_section_id)             \\\n    static int opt_show_##section(void *optctx, const char *opt, const char *arg) \\\n    {                                                                   \\\n        mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \\\n        return 0;                                                       \\\n    }\n\nDEFINE_OPT_SHOW_SECTION(chapters,         CHAPTERS)\nDEFINE_OPT_SHOW_SECTION(error,            ERROR)\nDEFINE_OPT_SHOW_SECTION(format,           FORMAT)\nDEFINE_OPT_SHOW_SECTION(frames,           FRAMES)\nDEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)\nDEFINE_OPT_SHOW_SECTION(packets,          PACKETS)\nDEFINE_OPT_SHOW_SECTION(pixel_formats,    PIXEL_FORMATS)\nDEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION)\nDEFINE_OPT_SHOW_SECTION(streams,          STREAMS)\nDEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS)\n\nstatic const OptionDef real_options[] = {\n    CMDUTILS_COMMON_OPTIONS\n    { \"f\", HAS_ARG, {.func_arg = opt_format}, \"force format\", \"format\" },\n    { \"unit\", OPT_BOOL, {&show_value_unit}, \"show unit of the displayed values\" },\n    { \"prefix\", OPT_BOOL, {&use_value_prefix}, \"use SI prefixes for the displayed values\" },\n    { \"byte_binary_prefix\", OPT_BOOL, {&use_byte_value_binary_prefix},\n      \"use binary prefixes for byte units\" },\n    { \"sexagesimal\", OPT_BOOL,  {&use_value_sexagesimal_format},\n      \"use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units\" },\n    { \"pretty\", 0, {.func_arg = opt_pretty},\n      \"prettify the format of displayed values, make it more human readable\" },\n    { \"print_format\", OPT_STRING | HAS_ARG, { &print_format },\n      \"set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)\", \"format\" },\n    { \"of\", OPT_STRING | HAS_ARG, { &print_format }, \"alias for -print_format\", \"format\" },\n    { \"select_streams\", OPT_STRING | HAS_ARG, { &stream_specifier }, \"select the specified streams\", \"stream_specifier\" },\n    { \"sections\", OPT_EXIT, {.func_arg = opt_sections}, \"print sections structure and section information, and exit\" },\n    { \"show_data\",    OPT_BOOL, { &do_show_data }, \"show packets data\" },\n    { \"show_data_hash\", OPT_STRING | HAS_ARG, { &show_data_hash }, \"show packets data hash\" },\n    { \"show_error\",   0, { .func_arg = &opt_show_error },  \"show probing error\" },\n    { \"show_format\",  0, { .func_arg = &opt_show_format }, \"show format/container info\" },\n    { \"show_frames\",  0, { .func_arg = &opt_show_frames }, \"show frames info\" },\n    { \"show_entries\", HAS_ARG, {.func_arg = opt_show_entries},\n      \"show a set of specified entries\", \"entry_list\" },\n#if HAVE_THREADS\n    { \"show_log\", OPT_INT|HAS_ARG, { &do_show_log }, \"show log\" },\n#endif\n    { \"show_packets\", 0, { .func_arg = &opt_show_packets }, \"show packets info\" },\n    { \"show_programs\", 0, { .func_arg = &opt_show_programs }, \"show programs info\" },\n    { \"show_streams\", 0, { .func_arg = &opt_show_streams }, \"show streams info\" },\n    { \"show_chapters\", 0, { .func_arg = &opt_show_chapters }, \"show chapters info\" },\n    { \"count_frames\", OPT_BOOL, { &do_count_frames }, \"count the number of frames per stream\" },\n    { \"count_packets\", OPT_BOOL, { &do_count_packets }, \"count the number of packets per stream\" },\n    { \"show_program_version\",  0, { .func_arg = &opt_show_program_version },  \"show ffprobe version\" },\n    { \"show_library_versions\", 0, { .func_arg = &opt_show_library_versions }, \"show library versions\" },\n    { \"show_versions\",         0, { .func_arg = &opt_show_versions }, \"show program and library versions\" },\n    { \"show_pixel_formats\", 0, { .func_arg = &opt_show_pixel_formats }, \"show pixel format descriptions\" },\n    { \"show_optional_fields\", HAS_ARG, { .func_arg = &opt_show_optional_fields }, \"show optional fields\" },\n    { \"show_private_data\", OPT_BOOL, { &show_private_data }, \"show private data\" },\n    { \"private\",           OPT_BOOL, { &show_private_data }, \"same as show_private_data\" },\n    { \"bitexact\", OPT_BOOL, {&do_bitexact}, \"force bitexact output\" },\n    { \"read_intervals\", HAS_ARG, {.func_arg = opt_read_intervals}, \"set read intervals\", \"read_intervals\" },\n    { \"i\", HAS_ARG, {.func_arg = opt_input_file_i}, \"read specified file\", \"input_file\"},\n    { \"o\", HAS_ARG, {.func_arg = opt_output_file_o}, \"write to specified output\", \"output_file\"},\n    { \"print_filename\", HAS_ARG, {.func_arg = opt_print_filename}, \"override the printed input filename\", \"print_file\"},\n    { \"find_stream_info\", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info },\n        \"read and decode the streams to fill missing information with heuristics\" },\n    { NULL, },\n};\n\nstatic inline int check_section_show_entries(int section_id)\n{\n    int *id;\n    struct section *section = &sections[section_id];\n    if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)\n        return 1;\n    for (id = section->children_ids; *id != -1; id++)\n        if (check_section_show_entries(*id))\n            return 1;\n    return 0;\n}\n\n#define SET_DO_SHOW(id, varname) do {                                   \\\n        if (check_section_show_entries(SECTION_ID_##id))                \\\n            do_show_##varname = 1;                                      \\\n    } while (0)\n\nint ffprobe(int argc, char **argv)\n{\n    const Writer *w;\n    WriterContext *wctx;\n    char *buf;\n    char *w_name = NULL, *w_args = NULL;\n    int ret, input_ret, i;\n\n    init_dynload();\n\n#if HAVE_THREADS\n    ret = pthread_mutex_init(&log_mutex, NULL);\n    if (ret != 0) {\n        goto end;\n    }\n#endif\n    av_log_set_flags(AV_LOG_SKIP_REPEATED);\n    ffprobe_cleanup(0);\n    register_exit(ffprobe_cleanup);\n\n    options = real_options;\n    parse_loglevel(argc, argv, options);\n    avformat_network_init();\n#if CONFIG_AVDEVICE\n    avdevice_register_all();\n#endif\n\n    show_banner(argc, argv, options);\n    parse_options(NULL, argc, argv, options, opt_input_file);\n\n    if (do_show_log)\n        av_log_set_callback(log_callback);\n\n    /* mark things to show, based on -show_entries */\n    SET_DO_SHOW(CHAPTERS, chapters);\n    SET_DO_SHOW(ERROR, error);\n    SET_DO_SHOW(FORMAT, format);\n    SET_DO_SHOW(FRAMES, frames);\n    SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);\n    SET_DO_SHOW(PACKETS, packets);\n    SET_DO_SHOW(PIXEL_FORMATS, pixel_formats);\n    SET_DO_SHOW(PIXEL_FORMAT_FLAGS, pixel_format_flags);\n    SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);\n    SET_DO_SHOW(PROGRAM_VERSION, program_version);\n    SET_DO_SHOW(PROGRAMS, programs);\n    SET_DO_SHOW(STREAMS, streams);\n    SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);\n    SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);\n\n    SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);\n    SET_DO_SHOW(FORMAT_TAGS, format_tags);\n    SET_DO_SHOW(FRAME_TAGS, frame_tags);\n    SET_DO_SHOW(PROGRAM_TAGS, program_tags);\n    SET_DO_SHOW(STREAM_TAGS, stream_tags);\n    SET_DO_SHOW(PROGRAM_STREAM_TAGS, stream_tags);\n    SET_DO_SHOW(PACKET_TAGS, packet_tags);\n\n    if (do_bitexact && (do_show_program_version || do_show_library_versions)) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"-bitexact and -show_program_version or -show_library_versions \"\n               \"options are incompatible\\n\");\n        ret = AVERROR(EINVAL);\n        goto end;\n    }\n\n    writer_register_all();\n\n    if (!print_format)\n        print_format = av_strdup(\"default\");\n    if (!print_format) {\n        ret = AVERROR(ENOMEM);\n        goto end;\n    }\n    w_name = av_strtok(print_format, \"=\", &buf);\n    if (!w_name) {\n        av_log(NULL, AV_LOG_ERROR,\n               \"No name specified for the output format\\n\");\n        ret = AVERROR(EINVAL);\n        goto end;\n    }\n    w_args = buf;\n\n    if (show_data_hash) {\n        if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) {\n            if (ret == AVERROR(EINVAL)) {\n                const char *n;\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Unknown hash algorithm '%s'\\nKnown algorithms:\",\n                       show_data_hash);\n                for (i = 0; (n = av_hash_names(i)); i++)\n                    av_log(NULL, AV_LOG_ERROR, \" %s\", n);\n                av_log(NULL, AV_LOG_ERROR, \"\\n\");\n            }\n            goto end;\n        }\n    }\n\n    w = writer_get_by_name(w_name);\n    if (!w) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown output format with name '%s'\\n\", w_name);\n        ret = AVERROR(EINVAL);\n        goto end;\n    }\n\n    if ((ret = writer_open(&wctx, w, w_args,\n                           sections, FF_ARRAY_ELEMS(sections), output_filename)) >= 0) {\n        if (w == &xml_writer)\n            wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES;\n\n        writer_print_section_header(wctx, SECTION_ID_ROOT);\n\n        if (do_show_program_version)\n            ffprobe_show_program_version(wctx);\n        if (do_show_library_versions)\n            ffprobe_show_library_versions(wctx);\n        if (do_show_pixel_formats)\n            ffprobe_show_pixel_formats(wctx);\n\n        if (!input_filename &&\n            ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||\n             (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {\n            show_usage();\n            av_log(NULL, AV_LOG_ERROR, \"You have to specify one input file.\\n\");\n            av_log(NULL, AV_LOG_ERROR, \"Use -h to get full help or, even better, run 'man %s'.\\n\", program_name_ffprobe);\n            ret = AVERROR(EINVAL);\n        } else if (input_filename) {\n            ret = probe_file(wctx, input_filename, print_input_filename);\n            if (ret < 0 && do_show_error)\n                show_error(wctx, ret);\n        }\n\n        input_ret = ret;\n\n        writer_print_section_footer(wctx);\n        ret = writer_close(&wctx);\n        if (ret < 0)\n            av_log(NULL, AV_LOG_ERROR, \"Writing output failed: %s\\n\", av_err2str(ret));\n\n        ret = FFMIN(ret, input_ret);\n    }\n\nend:\n    av_freep(&print_format);\n    av_freep(&read_intervals);\n    av_hash_freep(&hash);\n\n    uninit_opts();\n    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)\n        av_dict_free(&(sections[i].entries_to_show));\n\n    avformat_network_deinit();\n\n    return ret < 0;\n}\n"
  },
  {
    "path": "src/fftools/fopen_utf8.h",
    "content": "/*\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFTOOLS_FOPEN_UTF8_H\n#define FFTOOLS_FOPEN_UTF8_H\n\n#include <stdio.h>\n\n/* The fopen_utf8 function here is essentially equivalent to avpriv_fopen_utf8,\n * except that it doesn't set O_CLOEXEC, and that it isn't exported\n * from a different library. (On Windows, each DLL might use a different\n * CRT, and FILE* handles can't be shared across them.) */\n\n#ifdef _WIN32\n#include \"libavutil/wchar_filename.h\"\n\nstatic inline FILE *fopen_utf8(const char *path_utf8, const char *mode)\n{\n    wchar_t *path_w, *mode_w;\n    FILE *f;\n\n    /* convert UTF-8 to wide chars */\n    if (get_extended_win32_path(path_utf8, &path_w)) /* This sets errno on error. */\n        return NULL;\n    if (!path_w)\n        goto fallback;\n\n    if (utf8towchar(mode, &mode_w))\n        return NULL;\n    if (!mode_w) {\n        /* If failing to interpret the mode string as utf8, it is an invalid\n         * parameter. */\n        av_freep(&path_w);\n        errno = EINVAL;\n        return NULL;\n    }\n\n    f = _wfopen(path_w, mode_w);\n    av_freep(&path_w);\n    av_freep(&mode_w);\n\n    return f;\nfallback:\n    /* path may be in CP_ACP */\n    return fopen(path_utf8, mode);\n}\n\n#else\n\nstatic inline FILE *fopen_utf8(const char *path, const char *mode)\n{\n    return fopen(path, mode);\n}\n#endif\n\n#endif /* FFTOOLS_FOPEN_UTF8_H */\n"
  },
  {
    "path": "src/fftools/opt_common.c",
    "content": "/*\n * Option handlers shared between the tools.\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"config.h\"\n\n#include <stdio.h>\n\n#include \"cmdutils.h\"\n#include \"opt_common.h\"\n\n#include \"libavutil/avassert.h\"\n#include \"libavutil/avstring.h\"\n#include \"libavutil/bprint.h\"\n#include \"libavutil/channel_layout.h\"\n#include \"libavutil/cpu.h\"\n#include \"libavutil/dict.h\"\n#include \"libavutil/error.h\"\n#include \"libavutil/ffversion.h\"\n#include \"libavutil/log.h\"\n#include \"libavutil/mem.h\"\n#include \"libavutil/parseutils.h\"\n#include \"libavutil/pixdesc.h\"\n#include \"libavutil/version.h\"\n\n#include \"libavcodec/avcodec.h\"\n#include \"libavcodec/bsf.h\"\n#include \"libavcodec/codec.h\"\n#include \"libavcodec/codec_desc.h\"\n#include \"libavcodec/version.h\"\n\n#include \"libavformat/avformat.h\"\n#include \"libavformat/version.h\"\n\n#include \"libavdevice/avdevice.h\"\n#include \"libavdevice/version.h\"\n\n#include \"libavfilter/avfilter.h\"\n#include \"libavfilter/version.h\"\n\n#include \"libswscale/swscale.h\"\n#include \"libswscale/version.h\"\n\n#include \"libswresample/swresample.h\"\n#include \"libswresample/version.h\"\n\n#include \"libpostproc/postprocess.h\"\n#include \"libpostproc/version.h\"\n\nenum show_muxdemuxers {\n    SHOW_DEFAULT,\n    SHOW_DEMUXERS,\n    SHOW_MUXERS,\n};\n\nstatic FILE *report_file;\nstatic int report_file_level = AV_LOG_DEBUG;\n\nint show_license(void *optctx, const char *opt, const char *arg)\n{\n#if CONFIG_NONFREE\n    printf(\n    \"This version of %s has nonfree parts compiled in.\\n\"\n    \"Therefore it is not legally redistributable.\\n\",\n    program_name );\n#elif CONFIG_GPLV3\n    printf(\n    \"%s is free software; you can redistribute it and/or modify\\n\"\n    \"it under the terms of the GNU General Public License as published by\\n\"\n    \"the Free Software Foundation; either version 3 of the License, or\\n\"\n    \"(at your option) any later version.\\n\"\n    \"\\n\"\n    \"%s is distributed in the hope that it will be useful,\\n\"\n    \"but WITHOUT ANY WARRANTY; without even the implied warranty of\\n\"\n    \"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\\n\"\n    \"GNU General Public License for more details.\\n\"\n    \"\\n\"\n    \"You should have received a copy of the GNU General Public License\\n\"\n    \"along with %s.  If not, see <http://www.gnu.org/licenses/>.\\n\",\n    program_name, program_name, program_name );\n#elif CONFIG_GPL\n    printf(\n    \"%s is free software; you can redistribute it and/or modify\\n\"\n    \"it under the terms of the GNU General Public License as published by\\n\"\n    \"the Free Software Foundation; either version 2 of the License, or\\n\"\n    \"(at your option) any later version.\\n\"\n    \"\\n\"\n    \"%s is distributed in the hope that it will be useful,\\n\"\n    \"but WITHOUT ANY WARRANTY; without even the implied warranty of\\n\"\n    \"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\\n\"\n    \"GNU General Public License for more details.\\n\"\n    \"\\n\"\n    \"You should have received a copy of the GNU General Public License\\n\"\n    \"along with %s; if not, write to the Free Software\\n\"\n    \"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\\n\",\n    program_name, program_name, program_name );\n#elif CONFIG_LGPLV3\n    printf(\n    \"%s is free software; you can redistribute it and/or modify\\n\"\n    \"it under the terms of the GNU Lesser General Public License as published by\\n\"\n    \"the Free Software Foundation; either version 3 of the License, or\\n\"\n    \"(at your option) any later version.\\n\"\n    \"\\n\"\n    \"%s is distributed in the hope that it will be useful,\\n\"\n    \"but WITHOUT ANY WARRANTY; without even the implied warranty of\\n\"\n    \"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\\n\"\n    \"GNU Lesser General Public License for more details.\\n\"\n    \"\\n\"\n    \"You should have received a copy of the GNU Lesser General Public License\\n\"\n    \"along with %s.  If not, see <http://www.gnu.org/licenses/>.\\n\",\n    program_name, program_name, program_name );\n#else\n    printf(\n    \"%s is free software; you can redistribute it and/or\\n\"\n    \"modify it under the terms of the GNU Lesser General Public\\n\"\n    \"License as published by the Free Software Foundation; either\\n\"\n    \"version 2.1 of the License, or (at your option) any later version.\\n\"\n    \"\\n\"\n    \"%s is distributed in the hope that it will be useful,\\n\"\n    \"but WITHOUT ANY WARRANTY; without even the implied warranty of\\n\"\n    \"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\\n\"\n    \"Lesser General Public License for more details.\\n\"\n    \"\\n\"\n    \"You should have received a copy of the GNU Lesser General Public\\n\"\n    \"License along with %s; if not, write to the Free Software\\n\"\n    \"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\\n\",\n    program_name, program_name, program_name );\n#endif\n\n    return 0;\n}\n\nstatic int warned_cfg = 0;\n\n#define INDENT        1\n#define SHOW_VERSION  2\n#define SHOW_CONFIG   4\n#define SHOW_COPYRIGHT 8\n\n#define PRINT_LIB_INFO(libname, LIBNAME, flags, level)                  \\\n    if (CONFIG_##LIBNAME) {                                             \\\n        const char *indent = flags & INDENT? \"  \" : \"\";                 \\\n        if (flags & SHOW_VERSION) {                                     \\\n            unsigned int version = libname##_version();                 \\\n            av_log(NULL, level,                                         \\\n                   \"%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\\n\",            \\\n                   indent, #libname,                                    \\\n                   LIB##LIBNAME##_VERSION_MAJOR,                        \\\n                   LIB##LIBNAME##_VERSION_MINOR,                        \\\n                   LIB##LIBNAME##_VERSION_MICRO,                        \\\n                   AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\\\n                   AV_VERSION_MICRO(version));                          \\\n        }                                                               \\\n        if (flags & SHOW_CONFIG) {                                      \\\n            const char *cfg = libname##_configuration();                \\\n            if (strcmp(FFMPEG_CONFIGURATION, cfg)) {                    \\\n                if (!warned_cfg) {                                      \\\n                    av_log(NULL, level,                                 \\\n                            \"%sWARNING: library configuration mismatch\\n\", \\\n                            indent);                                    \\\n                    warned_cfg = 1;                                     \\\n                }                                                       \\\n                av_log(NULL, level, \"%s%-11s configuration: %s\\n\",      \\\n                        indent, #libname, cfg);                         \\\n            }                                                           \\\n        }                                                               \\\n    }                                                                   \\\n\nstatic void print_all_libs_info(int flags, int level)\n{\n    PRINT_LIB_INFO(avutil,     AVUTIL,     flags, level);\n    PRINT_LIB_INFO(avcodec,    AVCODEC,    flags, level);\n    PRINT_LIB_INFO(avformat,   AVFORMAT,   flags, level);\n    PRINT_LIB_INFO(avdevice,   AVDEVICE,   flags, level);\n    PRINT_LIB_INFO(avfilter,   AVFILTER,   flags, level);\n    PRINT_LIB_INFO(swscale,    SWSCALE,    flags, level);\n    PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);\n    PRINT_LIB_INFO(postproc,   POSTPROC,   flags, level);\n}\n\nstatic void print_program_info(int flags, int level)\n{\n    const char *indent = flags & INDENT? \"  \" : \"\";\n\n    av_log(NULL, level, \"%s version \" FFMPEG_VERSION, program_name);\n    if (flags & SHOW_COPYRIGHT)\n        av_log(NULL, level, \" Copyright (c) %d-%d the FFmpeg developers\",\n               program_birth_year, CONFIG_THIS_YEAR);\n    av_log(NULL, level, \"\\n\");\n    av_log(NULL, level, \"%sbuilt with %s\\n\", indent, CC_IDENT);\n\n    av_log(NULL, level, \"%sconfiguration: \" FFMPEG_CONFIGURATION \"\\n\", indent);\n}\n\nstatic void print_buildconf(int flags, int level)\n{\n    const char *indent = flags & INDENT ? \"  \" : \"\";\n    char str[] = { FFMPEG_CONFIGURATION };\n    char *conflist, *remove_tilde, *splitconf;\n\n    // Change all the ' --' strings to '~--' so that\n    // they can be identified as tokens.\n    while ((conflist = strstr(str, \" --\")) != NULL) {\n        conflist[0] = '~';\n    }\n\n    // Compensate for the weirdness this would cause\n    // when passing 'pkg-config --static'.\n    while ((remove_tilde = strstr(str, \"pkg-config~\")) != NULL) {\n        remove_tilde[sizeof(\"pkg-config~\") - 2] = ' ';\n    }\n\n    splitconf = strtok(str, \"~\");\n    av_log(NULL, level, \"\\n%sconfiguration:\\n\", indent);\n    while (splitconf != NULL) {\n        av_log(NULL, level, \"%s%s%s\\n\", indent, indent, splitconf);\n        splitconf = strtok(NULL, \"~\");\n    }\n}\n\nvoid show_banner(int argc, char **argv, const OptionDef *options)\n{\n    int idx = locate_option(argc, argv, options, \"version\");\n    if (hide_banner || idx)\n        return;\n\n    print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);\n    print_all_libs_info(INDENT|SHOW_CONFIG,  AV_LOG_INFO);\n    print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);\n}\n\nint show_version(void *optctx, const char *opt, const char *arg)\n{\n    av_log_set_callback(log_callback_help);\n    print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO);\n    print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);\n\n    return 0;\n}\n\nint show_buildconf(void *optctx, const char *opt, const char *arg)\n{\n    av_log_set_callback(log_callback_help);\n    print_buildconf      (INDENT|0, AV_LOG_INFO);\n\n    return 0;\n}\n\n#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \\\n    if (codec->field) {                                                      \\\n        const type *p = codec->field;                                        \\\n                                                                             \\\n        printf(\"    Supported \" list_name \":\");                              \\\n        while (*p != term) {                                                 \\\n            get_name(*p);                                                    \\\n            printf(\" %s\", name);                                             \\\n            p++;                                                             \\\n        }                                                                    \\\n        printf(\"\\n\");                                                        \\\n    }                                                                        \\\n\nstatic void print_codec(const AVCodec *c)\n{\n    int encoder = av_codec_is_encoder(c);\n\n    printf(\"%s %s [%s]:\\n\", encoder ? \"Encoder\" : \"Decoder\", c->name,\n           c->long_name ? c->long_name : \"\");\n\n    printf(\"    General capabilities: \");\n    if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)\n        printf(\"horizband \");\n    if (c->capabilities & AV_CODEC_CAP_DR1)\n        printf(\"dr1 \");\n    if (c->capabilities & AV_CODEC_CAP_DELAY)\n        printf(\"delay \");\n    if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)\n        printf(\"small \");\n    if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)\n        printf(\"subframes \");\n    if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)\n        printf(\"exp \");\n    if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)\n        printf(\"chconf \");\n    if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)\n        printf(\"paramchange \");\n    if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)\n        printf(\"variable \");\n    if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |\n                           AV_CODEC_CAP_SLICE_THREADS |\n                           AV_CODEC_CAP_OTHER_THREADS))\n        printf(\"threads \");\n    if (c->capabilities & AV_CODEC_CAP_AVOID_PROBING)\n        printf(\"avoidprobe \");\n    if (c->capabilities & AV_CODEC_CAP_HARDWARE)\n        printf(\"hardware \");\n    if (c->capabilities & AV_CODEC_CAP_HYBRID)\n        printf(\"hybrid \");\n    if (!c->capabilities)\n        printf(\"none\");\n    printf(\"\\n\");\n\n    if (c->type == AVMEDIA_TYPE_VIDEO ||\n        c->type == AVMEDIA_TYPE_AUDIO) {\n        printf(\"    Threading capabilities: \");\n        switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |\n                                   AV_CODEC_CAP_SLICE_THREADS |\n                                   AV_CODEC_CAP_OTHER_THREADS)) {\n        case AV_CODEC_CAP_FRAME_THREADS |\n             AV_CODEC_CAP_SLICE_THREADS: printf(\"frame and slice\"); break;\n        case AV_CODEC_CAP_FRAME_THREADS: printf(\"frame\");           break;\n        case AV_CODEC_CAP_SLICE_THREADS: printf(\"slice\");           break;\n        case AV_CODEC_CAP_OTHER_THREADS: printf(\"other\");           break;\n        default:                         printf(\"none\");            break;\n        }\n        printf(\"\\n\");\n    }\n\n    if (avcodec_get_hw_config(c, 0)) {\n        printf(\"    Supported hardware devices: \");\n        for (int i = 0;; i++) {\n            const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);\n            if (!config)\n                break;\n            printf(\"%s \", av_hwdevice_get_type_name(config->device_type));\n        }\n        printf(\"\\n\");\n    }\n\n    if (c->supported_framerates) {\n        const AVRational *fps = c->supported_framerates;\n\n        printf(\"    Supported framerates:\");\n        while (fps->num) {\n            printf(\" %d/%d\", fps->num, fps->den);\n            fps++;\n        }\n        printf(\"\\n\");\n    }\n    PRINT_CODEC_SUPPORTED(c, pix_fmts, enum AVPixelFormat, \"pixel formats\",\n                          AV_PIX_FMT_NONE, GET_PIX_FMT_NAME);\n    PRINT_CODEC_SUPPORTED(c, supported_samplerates, int, \"sample rates\", 0,\n                          GET_SAMPLE_RATE_NAME);\n    PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, \"sample formats\",\n                          AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME);\n\n    if (c->ch_layouts) {\n        const AVChannelLayout *p = c->ch_layouts;\n\n        printf(\"    Supported channel layouts:\");\n        while (p->nb_channels) {\n            char name[128];\n            av_channel_layout_describe(p, name, sizeof(name));\n            printf(\" %s\", name);\n            p++;\n        }\n        printf(\"\\n\");\n    }\n\n    if (c->priv_class) {\n        show_help_children(c->priv_class,\n                           AV_OPT_FLAG_ENCODING_PARAM |\n                           AV_OPT_FLAG_DECODING_PARAM);\n    }\n}\n\nstatic const AVCodec *next_codec_for_id(enum AVCodecID id, void **iter,\n                                        int encoder)\n{\n    const AVCodec *c;\n    while ((c = av_codec_iterate(iter))) {\n        if (c->id == id &&\n            (encoder ? av_codec_is_encoder(c) : av_codec_is_decoder(c)))\n            return c;\n    }\n    return NULL;\n}\n\nstatic void show_help_codec(const char *name, int encoder)\n{\n    const AVCodecDescriptor *desc;\n    const AVCodec *codec;\n\n    if (!name) {\n        av_log(NULL, AV_LOG_ERROR, \"No codec name specified.\\n\");\n        return;\n    }\n\n    codec = encoder ? avcodec_find_encoder_by_name(name) :\n                      avcodec_find_decoder_by_name(name);\n\n    if (codec)\n        print_codec(codec);\n    else if ((desc = avcodec_descriptor_get_by_name(name))) {\n        void *iter = NULL;\n        int printed = 0;\n\n        while ((codec = next_codec_for_id(desc->id, &iter, encoder))) {\n            printed = 1;\n            print_codec(codec);\n        }\n\n        if (!printed) {\n            av_log(NULL, AV_LOG_ERROR, \"Codec '%s' is known to FFmpeg, \"\n                   \"but no %s for it are available. FFmpeg might need to be \"\n                   \"recompiled with additional external libraries.\\n\",\n                   name, encoder ? \"encoders\" : \"decoders\");\n        }\n    } else {\n        av_log(NULL, AV_LOG_ERROR, \"Codec '%s' is not recognized by FFmpeg.\\n\",\n               name);\n    }\n}\n\nstatic void show_help_demuxer(const char *name)\n{\n    const AVInputFormat *fmt = av_find_input_format(name);\n\n    if (!fmt) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown format '%s'.\\n\", name);\n        return;\n    }\n\n    printf(\"Demuxer %s [%s]:\\n\", fmt->name, fmt->long_name);\n\n    if (fmt->extensions)\n        printf(\"    Common extensions: %s.\\n\", fmt->extensions);\n\n    if (fmt->priv_class)\n        show_help_children(fmt->priv_class, AV_OPT_FLAG_DECODING_PARAM);\n}\n\nstatic void show_help_protocol(const char *name)\n{\n    const AVClass *proto_class;\n\n    if (!name) {\n        av_log(NULL, AV_LOG_ERROR, \"No protocol name specified.\\n\");\n        return;\n    }\n\n    proto_class = avio_protocol_get_class(name);\n    if (!proto_class) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown protocol '%s'.\\n\", name);\n        return;\n    }\n\n    show_help_children(proto_class, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM);\n}\n\nstatic void show_help_muxer(const char *name)\n{\n    const AVCodecDescriptor *desc;\n    const AVOutputFormat *fmt = av_guess_format(name, NULL, NULL);\n\n    if (!fmt) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown format '%s'.\\n\", name);\n        return;\n    }\n\n    printf(\"Muxer %s [%s]:\\n\", fmt->name, fmt->long_name);\n\n    if (fmt->extensions)\n        printf(\"    Common extensions: %s.\\n\", fmt->extensions);\n    if (fmt->mime_type)\n        printf(\"    Mime type: %s.\\n\", fmt->mime_type);\n    if (fmt->video_codec != AV_CODEC_ID_NONE &&\n        (desc = avcodec_descriptor_get(fmt->video_codec))) {\n        printf(\"    Default video codec: %s.\\n\", desc->name);\n    }\n    if (fmt->audio_codec != AV_CODEC_ID_NONE &&\n        (desc = avcodec_descriptor_get(fmt->audio_codec))) {\n        printf(\"    Default audio codec: %s.\\n\", desc->name);\n    }\n    if (fmt->subtitle_codec != AV_CODEC_ID_NONE &&\n        (desc = avcodec_descriptor_get(fmt->subtitle_codec))) {\n        printf(\"    Default subtitle codec: %s.\\n\", desc->name);\n    }\n\n    if (fmt->priv_class)\n        show_help_children(fmt->priv_class, AV_OPT_FLAG_ENCODING_PARAM);\n}\n\n#if CONFIG_AVFILTER\nstatic void show_help_filter(const char *name)\n{\n#if CONFIG_AVFILTER\n    const AVFilter *f = avfilter_get_by_name(name);\n    int i, count;\n\n    if (!name) {\n        av_log(NULL, AV_LOG_ERROR, \"No filter name specified.\\n\");\n        return;\n    } else if (!f) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown filter '%s'.\\n\", name);\n        return;\n    }\n\n    printf(\"Filter %s\\n\", f->name);\n    if (f->description)\n        printf(\"  %s\\n\", f->description);\n\n    if (f->flags & AVFILTER_FLAG_SLICE_THREADS)\n        printf(\"    slice threading supported\\n\");\n\n    printf(\"    Inputs:\\n\");\n    count = avfilter_filter_pad_count(f, 0);\n    for (i = 0; i < count; i++) {\n        printf(\"       #%d: %s (%s)\\n\", i, avfilter_pad_get_name(f->inputs, i),\n               av_get_media_type_string(avfilter_pad_get_type(f->inputs, i)));\n    }\n    if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)\n        printf(\"        dynamic (depending on the options)\\n\");\n    else if (!count)\n        printf(\"        none (source filter)\\n\");\n\n    printf(\"    Outputs:\\n\");\n    count = avfilter_filter_pad_count(f, 1);\n    for (i = 0; i < count; i++) {\n        printf(\"       #%d: %s (%s)\\n\", i, avfilter_pad_get_name(f->outputs, i),\n               av_get_media_type_string(avfilter_pad_get_type(f->outputs, i)));\n    }\n    if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS)\n        printf(\"        dynamic (depending on the options)\\n\");\n    else if (!count)\n        printf(\"        none (sink filter)\\n\");\n\n    if (f->priv_class)\n        show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |\n                                          AV_OPT_FLAG_AUDIO_PARAM);\n    if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)\n        printf(\"This filter has support for timeline through the 'enable' option.\\n\");\n#else\n    av_log(NULL, AV_LOG_ERROR, \"Build without libavfilter; \"\n           \"can not to satisfy request\\n\");\n#endif\n}\n#endif\n\nstatic void show_help_bsf(const char *name)\n{\n    const AVBitStreamFilter *bsf = av_bsf_get_by_name(name);\n\n    if (!name) {\n        av_log(NULL, AV_LOG_ERROR, \"No bitstream filter name specified.\\n\");\n        return;\n    } else if (!bsf) {\n        av_log(NULL, AV_LOG_ERROR, \"Unknown bit stream filter '%s'.\\n\", name);\n        return;\n    }\n\n    printf(\"Bit stream filter %s\\n\", bsf->name);\n    PRINT_CODEC_SUPPORTED(bsf, codec_ids, enum AVCodecID, \"codecs\",\n                          AV_CODEC_ID_NONE, GET_CODEC_NAME);\n    if (bsf->priv_class)\n        show_help_children(bsf->priv_class, AV_OPT_FLAG_BSF_PARAM);\n}\n\nint show_help(void *optctx, const char *opt, const char *arg)\n{\n    char *topic, *par;\n    av_log_set_callback(log_callback_help);\n\n    topic = av_strdup(arg ? arg : \"\");\n    if (!topic)\n        return AVERROR(ENOMEM);\n    par = strchr(topic, '=');\n    if (par)\n        *par++ = 0;\n\n    if (!*topic) {\n        show_help_default(topic, par);\n    } else if (!strcmp(topic, \"decoder\")) {\n        show_help_codec(par, 0);\n    } else if (!strcmp(topic, \"encoder\")) {\n        show_help_codec(par, 1);\n    } else if (!strcmp(topic, \"demuxer\")) {\n        show_help_demuxer(par);\n    } else if (!strcmp(topic, \"muxer\")) {\n        show_help_muxer(par);\n    } else if (!strcmp(topic, \"protocol\")) {\n        show_help_protocol(par);\n#if CONFIG_AVFILTER\n    } else if (!strcmp(topic, \"filter\")) {\n        show_help_filter(par);\n#endif\n    } else if (!strcmp(topic, \"bsf\")) {\n        show_help_bsf(par);\n    } else {\n        show_help_default(topic, par);\n    }\n\n    av_freep(&topic);\n    return 0;\n}\n\nstatic void print_codecs_for_id(enum AVCodecID id, int encoder)\n{\n    void *iter = NULL;\n    const AVCodec *codec;\n\n    printf(\" (%s: \", encoder ? \"encoders\" : \"decoders\");\n\n    while ((codec = next_codec_for_id(id, &iter, encoder)))\n        printf(\"%s \", codec->name);\n\n    printf(\")\");\n}\n\nstatic int compare_codec_desc(const void *a, const void *b)\n{\n    const AVCodecDescriptor * const *da = a;\n    const AVCodecDescriptor * const *db = b;\n\n    return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :\n           strcmp((*da)->name, (*db)->name);\n}\n\nstatic unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)\n{\n    const AVCodecDescriptor *desc = NULL;\n    const AVCodecDescriptor **codecs;\n    unsigned nb_codecs = 0, i = 0;\n\n    while ((desc = avcodec_descriptor_next(desc)))\n        nb_codecs++;\n    if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) {\n        av_log(NULL, AV_LOG_ERROR, \"Out of memory\\n\");\n        exit_program(1);\n    }\n    desc = NULL;\n    while ((desc = avcodec_descriptor_next(desc)))\n        codecs[i++] = desc;\n    av_assert0(i == nb_codecs);\n    qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);\n    *rcodecs = codecs;\n    return nb_codecs;\n}\n\nstatic char get_media_type_char(enum AVMediaType type)\n{\n    switch (type) {\n        case AVMEDIA_TYPE_VIDEO:    return 'V';\n        case AVMEDIA_TYPE_AUDIO:    return 'A';\n        case AVMEDIA_TYPE_DATA:     return 'D';\n        case AVMEDIA_TYPE_SUBTITLE: return 'S';\n        case AVMEDIA_TYPE_ATTACHMENT:return 'T';\n        default:                    return '?';\n    }\n}\n\nint show_codecs(void *optctx, const char *opt, const char *arg)\n{\n    const AVCodecDescriptor **codecs;\n    unsigned i, nb_codecs = get_codecs_sorted(&codecs);\n\n    printf(\"Codecs:\\n\"\n           \" D..... = Decoding supported\\n\"\n           \" .E.... = Encoding supported\\n\"\n           \" ..V... = Video codec\\n\"\n           \" ..A... = Audio codec\\n\"\n           \" ..S... = Subtitle codec\\n\"\n           \" ..D... = Data codec\\n\"\n           \" ..T... = Attachment codec\\n\"\n           \" ...I.. = Intra frame-only codec\\n\"\n           \" ....L. = Lossy compression\\n\"\n           \" .....S = Lossless compression\\n\"\n           \" -------\\n\");\n    for (i = 0; i < nb_codecs; i++) {\n        const AVCodecDescriptor *desc = codecs[i];\n        const AVCodec *codec;\n        void *iter = NULL;\n\n        if (strstr(desc->name, \"_deprecated\"))\n            continue;\n\n        printf(\" \");\n        printf(avcodec_find_decoder(desc->id) ? \"D\" : \".\");\n        printf(avcodec_find_encoder(desc->id) ? \"E\" : \".\");\n\n        printf(\"%c\", get_media_type_char(desc->type));\n        printf((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? \"I\" : \".\");\n        printf((desc->props & AV_CODEC_PROP_LOSSY)      ? \"L\" : \".\");\n        printf((desc->props & AV_CODEC_PROP_LOSSLESS)   ? \"S\" : \".\");\n\n        printf(\" %-20s %s\", desc->name, desc->long_name ? desc->long_name : \"\");\n\n        /* print decoders/encoders when there's more than one or their\n         * names are different from codec name */\n        while ((codec = next_codec_for_id(desc->id, &iter, 0))) {\n            if (strcmp(codec->name, desc->name)) {\n                print_codecs_for_id(desc->id, 0);\n                break;\n            }\n        }\n        iter = NULL;\n        while ((codec = next_codec_for_id(desc->id, &iter, 1))) {\n            if (strcmp(codec->name, desc->name)) {\n                print_codecs_for_id(desc->id, 1);\n                break;\n            }\n        }\n\n        printf(\"\\n\");\n    }\n    av_free(codecs);\n    return 0;\n}\n\nstatic void print_codecs(int encoder)\n{\n    const AVCodecDescriptor **codecs;\n    unsigned i, nb_codecs = get_codecs_sorted(&codecs);\n\n    printf(\"%s:\\n\"\n           \" V..... = Video\\n\"\n           \" A..... = Audio\\n\"\n           \" S..... = Subtitle\\n\"\n           \" .F.... = Frame-level multithreading\\n\"\n           \" ..S... = Slice-level multithreading\\n\"\n           \" ...X.. = Codec is experimental\\n\"\n           \" ....B. = Supports draw_horiz_band\\n\"\n           \" .....D = Supports direct rendering method 1\\n\"\n           \" ------\\n\",\n           encoder ? \"Encoders\" : \"Decoders\");\n    for (i = 0; i < nb_codecs; i++) {\n        const AVCodecDescriptor *desc = codecs[i];\n        const AVCodec *codec;\n        void *iter = NULL;\n\n        while ((codec = next_codec_for_id(desc->id, &iter, encoder))) {\n            printf(\" %c\", get_media_type_char(desc->type));\n            printf((codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) ? \"F\" : \".\");\n            printf((codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) ? \"S\" : \".\");\n            printf((codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)  ? \"X\" : \".\");\n            printf((codec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)?\"B\" : \".\");\n            printf((codec->capabilities & AV_CODEC_CAP_DR1)           ? \"D\" : \".\");\n\n            printf(\" %-20s %s\", codec->name, codec->long_name ? codec->long_name : \"\");\n            if (strcmp(codec->name, desc->name))\n                printf(\" (codec %s)\", desc->name);\n\n            printf(\"\\n\");\n        }\n    }\n    av_free(codecs);\n}\n\nint show_decoders(void *optctx, const char *opt, const char *arg)\n{\n    print_codecs(0);\n    return 0;\n}\n\nint show_encoders(void *optctx, const char *opt, const char *arg)\n{\n    print_codecs(1);\n    return 0;\n}\n\nint show_bsfs(void *optctx, const char *opt, const char *arg)\n{\n    const AVBitStreamFilter *bsf = NULL;\n    void *opaque = NULL;\n\n    printf(\"Bitstream filters:\\n\");\n    while ((bsf = av_bsf_iterate(&opaque)))\n        printf(\"%s\\n\", bsf->name);\n    printf(\"\\n\");\n    return 0;\n}\n\nint show_filters(void *optctx, const char *opt, const char *arg)\n{\n#if CONFIG_AVFILTER\n    const AVFilter *filter = NULL;\n    char descr[64], *descr_cur;\n    void *opaque = NULL;\n    int i, j;\n    const AVFilterPad *pad;\n\n    printf(\"Filters:\\n\"\n           \"  T.. = Timeline support\\n\"\n           \"  .S. = Slice threading\\n\"\n           \"  ..C = Command support\\n\"\n           \"  A = Audio input/output\\n\"\n           \"  V = Video input/output\\n\"\n           \"  N = Dynamic number and/or type of input/output\\n\"\n           \"  | = Source or sink filter\\n\");\n    while ((filter = av_filter_iterate(&opaque))) {\n        descr_cur = descr;\n        for (i = 0; i < 2; i++) {\n            unsigned nb_pads;\n            if (i) {\n                *(descr_cur++) = '-';\n                *(descr_cur++) = '>';\n            }\n            pad = i ? filter->outputs : filter->inputs;\n            nb_pads = avfilter_filter_pad_count(filter, i);\n            for (j = 0; j < nb_pads; j++) {\n                if (descr_cur >= descr + sizeof(descr) - 4)\n                    break;\n                *(descr_cur++) = get_media_type_char(avfilter_pad_get_type(pad, j));\n            }\n            if (!j)\n                *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||\n                                  ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';\n        }\n        *descr_cur = 0;\n        printf(\" %c%c%c %-17s %-10s %s\\n\",\n               filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',\n               filter->flags & AVFILTER_FLAG_SLICE_THREADS    ? 'S' : '.',\n               filter->process_command                        ? 'C' : '.',\n               filter->name, descr, filter->description);\n    }\n#else\n    printf(\"No filters available: libavfilter disabled\\n\");\n#endif\n    return 0;\n}\n\nstatic int is_device(const AVClass *avclass)\n{\n    if (!avclass)\n        return 0;\n    return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category);\n}\n\nstatic int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers)\n{\n    void *ifmt_opaque = NULL;\n    const AVInputFormat *ifmt  = NULL;\n    void *ofmt_opaque = NULL;\n    const AVOutputFormat *ofmt = NULL;\n    const char *last_name;\n    int is_dev;\n\n    printf(\"%s\\n\"\n           \" D. = Demuxing supported\\n\"\n           \" .E = Muxing supported\\n\"\n           \" --\\n\", device_only ? \"Devices:\" : \"File formats:\");\n    last_name = \"000\";\n    for (;;) {\n        int decode = 0;\n        int encode = 0;\n        const char *name      = NULL;\n        const char *long_name = NULL;\n\n        if (muxdemuxers !=SHOW_DEMUXERS) {\n            ofmt_opaque = NULL;\n            while ((ofmt = av_muxer_iterate(&ofmt_opaque))) {\n                is_dev = is_device(ofmt->priv_class);\n                if (!is_dev && device_only)\n                    continue;\n                if ((!name || strcmp(ofmt->name, name) < 0) &&\n                    strcmp(ofmt->name, last_name) > 0) {\n                    name      = ofmt->name;\n                    long_name = ofmt->long_name;\n                    encode    = 1;\n                }\n            }\n        }\n        if (muxdemuxers != SHOW_MUXERS) {\n            ifmt_opaque = NULL;\n            while ((ifmt = av_demuxer_iterate(&ifmt_opaque))) {\n                is_dev = is_device(ifmt->priv_class);\n                if (!is_dev && device_only)\n                    continue;\n                if ((!name || strcmp(ifmt->name, name) < 0) &&\n                    strcmp(ifmt->name, last_name) > 0) {\n                    name      = ifmt->name;\n                    long_name = ifmt->long_name;\n                    encode    = 0;\n                }\n                if (name && strcmp(ifmt->name, name) == 0)\n                    decode = 1;\n            }\n        }\n        if (!name)\n            break;\n        last_name = name;\n\n        printf(\" %c%c %-15s %s\\n\",\n               decode ? 'D' : ' ',\n               encode ? 'E' : ' ',\n               name,\n            long_name ? long_name:\" \");\n    }\n    return 0;\n}\n\nint show_formats(void *optctx, const char *opt, const char *arg)\n{\n    return show_formats_devices(optctx, opt, arg, 0, SHOW_DEFAULT);\n}\n\nint show_muxers(void *optctx, const char *opt, const char *arg)\n{\n    return show_formats_devices(optctx, opt, arg, 0, SHOW_MUXERS);\n}\n\nint show_demuxers(void *optctx, const char *opt, const char *arg)\n{\n    return show_formats_devices(optctx, opt, arg, 0, SHOW_DEMUXERS);\n}\n\nint show_devices(void *optctx, const char *opt, const char *arg)\n{\n    return show_formats_devices(optctx, opt, arg, 1, SHOW_DEFAULT);\n}\n\nint show_protocols(void *optctx, const char *opt, const char *arg)\n{\n    void *opaque = NULL;\n    const char *name;\n\n    printf(\"Supported file protocols:\\n\"\n           \"Input:\\n\");\n    while ((name = avio_enum_protocols(&opaque, 0)))\n        printf(\"  %s\\n\", name);\n    printf(\"Output:\\n\");\n    while ((name = avio_enum_protocols(&opaque, 1)))\n        printf(\"  %s\\n\", name);\n    return 0;\n}\n\nint show_colors(void *optctx, const char *opt, const char *arg)\n{\n    const char *name;\n    const uint8_t *rgb;\n    int i;\n\n    printf(\"%-32s #RRGGBB\\n\", \"name\");\n\n    for (i = 0; name = av_get_known_color_name(i, &rgb); i++)\n        printf(\"%-32s #%02x%02x%02x\\n\", name, rgb[0], rgb[1], rgb[2]);\n\n    return 0;\n}\n\nint show_pix_fmts(void *optctx, const char *opt, const char *arg)\n{\n    const AVPixFmtDescriptor *pix_desc = NULL;\n\n    printf(\"Pixel formats:\\n\"\n           \"I.... = Supported Input  format for conversion\\n\"\n           \".O... = Supported Output format for conversion\\n\"\n           \"..H.. = Hardware accelerated format\\n\"\n           \"...P. = Paletted format\\n\"\n           \"....B = Bitstream format\\n\"\n           \"FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL BIT_DEPTHS\\n\"\n           \"-----\\n\");\n\n#if !CONFIG_SWSCALE\n#   define sws_isSupportedInput(x)  0\n#   define sws_isSupportedOutput(x) 0\n#endif\n\n    while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) {\n        enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc);\n        printf(\"%c%c%c%c%c %-16s       %d            %3d      %d\",\n               sws_isSupportedInput (pix_fmt)              ? 'I' : '.',\n               sws_isSupportedOutput(pix_fmt)              ? 'O' : '.',\n               pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL   ? 'H' : '.',\n               pix_desc->flags & AV_PIX_FMT_FLAG_PAL       ? 'P' : '.',\n               pix_desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ? 'B' : '.',\n               pix_desc->name,\n               pix_desc->nb_components,\n               av_get_bits_per_pixel(pix_desc),\n               pix_desc->comp[0].depth);\n\n        for (unsigned i = 1; i < pix_desc->nb_components; i++)\n            printf(\"-%d\", pix_desc->comp[i].depth);\n        printf(\"\\n\");\n    }\n    return 0;\n}\n\nint show_layouts(void *optctx, const char *opt, const char *arg)\n{\n    const AVChannelLayout *ch_layout;\n    void *iter = NULL;\n    char buf[128], buf2[128];\n    int i = 0;\n\n    printf(\"Individual channels:\\n\"\n           \"NAME           DESCRIPTION\\n\");\n    for (i = 0; i < 63; i++) {\n        av_channel_name(buf, sizeof(buf), i);\n        if (strstr(buf, \"USR\"))\n            continue;\n        av_channel_description(buf2, sizeof(buf2), i);\n        printf(\"%-14s %s\\n\", buf, buf2);\n    }\n    printf(\"\\nStandard channel layouts:\\n\"\n           \"NAME           DECOMPOSITION\\n\");\n    while (ch_layout = av_channel_layout_standard(&iter)) {\n            av_channel_layout_describe(ch_layout, buf, sizeof(buf));\n            printf(\"%-14s \", buf);\n            for (i = 0; i < 63; i++) {\n                int idx = av_channel_layout_index_from_channel(ch_layout, i);\n                if (idx >= 0) {\n                    av_channel_name(buf2, sizeof(buf2), i);\n                    printf(\"%s%s\", idx ? \"+\" : \"\", buf2);\n                }\n            }\n            printf(\"\\n\");\n    }\n    return 0;\n}\n\nint show_sample_fmts(void *optctx, const char *opt, const char *arg)\n{\n    int i;\n    char fmt_str[128];\n    for (i = -1; i < AV_SAMPLE_FMT_NB; i++)\n        printf(\"%s\\n\", av_get_sample_fmt_string(fmt_str, sizeof(fmt_str), i));\n    return 0;\n}\n\nint show_dispositions(void *optctx, const char *opt, const char *arg)\n{\n    for (int i = 0; i < 32; i++) {\n        const char *str = av_disposition_to_string(1U << i);\n        if (str)\n            printf(\"%s\\n\", str);\n    }\n    return 0;\n}\n\nint opt_cpuflags(void *optctx, const char *opt, const char *arg)\n{\n    int ret;\n    unsigned flags = av_get_cpu_flags();\n\n    if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)\n        return ret;\n\n    av_force_cpu_flags(flags);\n    return 0;\n}\n\nint opt_cpucount(void *optctx, const char *opt, const char *arg)\n{\n    int ret;\n    int count;\n\n    static const AVOption opts[] = {\n        {\"count\", NULL, 0, AV_OPT_TYPE_INT, { .i64 = -1}, -1, INT_MAX},\n        {NULL},\n    };\n    static const AVClass class = {\n        .class_name = \"cpucount\",\n        .item_name  = av_default_item_name,\n        .option     = opts,\n        .version    = LIBAVUTIL_VERSION_INT,\n    };\n    const AVClass *pclass = &class;\n\n    ret = av_opt_eval_int(&pclass, opts, arg, &count);\n\n    if (!ret) {\n        av_cpu_force_count(count);\n    }\n\n    return ret;\n}\n\nstatic void expand_filename_template(AVBPrint *bp, const char *template,\n                                     struct tm *tm)\n{\n    int c;\n\n    while ((c = *(template++))) {\n        if (c == '%') {\n            if (!(c = *(template++)))\n                break;\n            switch (c) {\n            case 'p':\n                av_bprintf(bp, \"%s\", program_name);\n                break;\n            case 't':\n                av_bprintf(bp, \"%04d%02d%02d-%02d%02d%02d\",\n                           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,\n                           tm->tm_hour, tm->tm_min, tm->tm_sec);\n                break;\n            case '%':\n                av_bprint_chars(bp, c, 1);\n                break;\n            }\n        } else {\n            av_bprint_chars(bp, c, 1);\n        }\n    }\n}\n\nstatic void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)\n{\n    va_list vl2;\n    char line[1024];\n    static int print_prefix = 1;\n\n    va_copy(vl2, vl);\n    av_log_default_callback(ptr, level, fmt, vl);\n    av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);\n    va_end(vl2);\n    if (report_file_level >= level) {\n        fputs(line, report_file);\n        fflush(report_file);\n    }\n}\n\nint init_report(const char *env, FILE **file)\n{\n    char *filename_template = NULL;\n    char *key, *val;\n    int ret, count = 0;\n    int prog_loglevel, envlevel = 0;\n    time_t now;\n    struct tm *tm;\n    AVBPrint filename;\n\n    if (report_file) /* already opened */\n        return 0;\n    time(&now);\n    tm = localtime(&now);\n\n    while (env && *env) {\n        if ((ret = av_opt_get_key_value(&env, \"=\", \":\", 0, &key, &val)) < 0) {\n            if (count)\n                av_log(NULL, AV_LOG_ERROR,\n                       \"Failed to parse FFREPORT environment variable: %s\\n\",\n                       av_err2str(ret));\n            break;\n        }\n        if (*env)\n            env++;\n        count++;\n        if (!strcmp(key, \"file\")) {\n            av_free(filename_template);\n            filename_template = val;\n            val = NULL;\n        } else if (!strcmp(key, \"level\")) {\n            char *tail;\n            report_file_level = strtol(val, &tail, 10);\n            if (*tail) {\n                av_log(NULL, AV_LOG_FATAL, \"Invalid report file level\\n\");\n                exit_program(1);\n            }\n            envlevel = 1;\n        } else {\n            av_log(NULL, AV_LOG_ERROR, \"Unknown key '%s' in FFREPORT\\n\", key);\n        }\n        av_free(val);\n        av_free(key);\n    }\n\n    av_bprint_init(&filename, 0, AV_BPRINT_SIZE_AUTOMATIC);\n    expand_filename_template(&filename,\n                             av_x_if_null(filename_template, \"%p-%t.log\"), tm);\n    av_free(filename_template);\n    if (!av_bprint_is_complete(&filename)) {\n        av_log(NULL, AV_LOG_ERROR, \"Out of memory building report file name\\n\");\n        return AVERROR(ENOMEM);\n    }\n\n    prog_loglevel = av_log_get_level();\n    if (!envlevel)\n        report_file_level = FFMAX(report_file_level, prog_loglevel);\n\n    report_file = fopen(filename.str, \"w\");\n    if (!report_file) {\n        int ret = AVERROR(errno);\n        av_log(NULL, AV_LOG_ERROR, \"Failed to open report \\\"%s\\\": %s\\n\",\n               filename.str, strerror(errno));\n        return ret;\n    }\n    av_log_set_callback(log_callback_report);\n    av_log(NULL, AV_LOG_INFO,\n           \"%s started on %04d-%02d-%02d at %02d:%02d:%02d\\n\"\n           \"Report written to \\\"%s\\\"\\n\"\n           \"Log level: %d\\n\",\n           program_name,\n           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,\n           tm->tm_hour, tm->tm_min, tm->tm_sec,\n           filename.str, report_file_level);\n    av_bprint_finalize(&filename, NULL);\n\n    if (file)\n        *file = report_file;\n\n    return 0;\n}\n\nint opt_report(void *optctx, const char *opt, const char *arg)\n{\n    return init_report(NULL, NULL);\n}\n\nint opt_max_alloc(void *optctx, const char *opt, const char *arg)\n{\n    char *tail;\n    size_t max;\n\n    max = strtol(arg, &tail, 10);\n    if (*tail) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid max_alloc \\\"%s\\\".\\n\", arg);\n        exit_program(1);\n    }\n    av_max_alloc(max);\n    return 0;\n}\n\nint opt_loglevel(void *optctx, const char *opt, const char *arg)\n{\n    const struct { const char *name; int level; } log_levels[] = {\n        { \"quiet\"  , AV_LOG_QUIET   },\n        { \"panic\"  , AV_LOG_PANIC   },\n        { \"fatal\"  , AV_LOG_FATAL   },\n        { \"error\"  , AV_LOG_ERROR   },\n        { \"warning\", AV_LOG_WARNING },\n        { \"info\"   , AV_LOG_INFO    },\n        { \"verbose\", AV_LOG_VERBOSE },\n        { \"debug\"  , AV_LOG_DEBUG   },\n        { \"trace\"  , AV_LOG_TRACE   },\n    };\n    const char *token;\n    char *tail;\n    int flags = av_log_get_flags();\n    int level = av_log_get_level();\n    int cmd, i = 0;\n\n    av_assert0(arg);\n    while (*arg) {\n        token = arg;\n        if (*token == '+' || *token == '-') {\n            cmd = *token++;\n        } else {\n            cmd = 0;\n        }\n        if (!i && !cmd) {\n            flags = 0;  /* missing relative prefix, build absolute value */\n        }\n        if (av_strstart(token, \"repeat\", &arg)) {\n            if (cmd == '-') {\n                flags |= AV_LOG_SKIP_REPEATED;\n            } else {\n                flags &= ~AV_LOG_SKIP_REPEATED;\n            }\n        } else if (av_strstart(token, \"level\", &arg)) {\n            if (cmd == '-') {\n                flags &= ~AV_LOG_PRINT_LEVEL;\n            } else {\n                flags |= AV_LOG_PRINT_LEVEL;\n            }\n        } else {\n            break;\n        }\n        i++;\n    }\n    if (!*arg) {\n        goto end;\n    } else if (*arg == '+') {\n        arg++;\n    } else if (!i) {\n        flags = av_log_get_flags();  /* level value without prefix, reset flags */\n    }\n\n    for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {\n        if (!strcmp(log_levels[i].name, arg)) {\n            level = log_levels[i].level;\n            goto end;\n        }\n    }\n\n    level = strtol(arg, &tail, 10);\n    if (*tail) {\n        av_log(NULL, AV_LOG_FATAL, \"Invalid loglevel \\\"%s\\\". \"\n               \"Possible levels are numbers or:\\n\", arg);\n        for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++)\n            av_log(NULL, AV_LOG_FATAL, \"\\\"%s\\\"\\n\", log_levels[i].name);\n        exit_program(1);\n    }\n\nend:\n    av_log_set_flags(flags);\n    av_log_set_level(level);\n    return 0;\n}\n\n#if CONFIG_AVDEVICE\nstatic void print_device_list(const AVDeviceInfoList *device_list)\n{\n    // print devices\n    for (int i = 0; i < device_list->nb_devices; i++) {\n        const AVDeviceInfo *device = device_list->devices[i];\n        printf(\"%c %s [%s] (\", device_list->default_device == i ? '*' : ' ',\n            device->device_name, device->device_description);\n        if (device->nb_media_types > 0) {\n            for (int j = 0; j < device->nb_media_types; ++j) {\n                const char* media_type = av_get_media_type_string(device->media_types[j]);\n                if (j > 0)\n                    printf(\", \");\n                printf(\"%s\", media_type ? media_type : \"unknown\");\n            }\n        } else {\n            printf(\"none\");\n        }\n        printf(\")\\n\");\n    }\n}\n\nstatic int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)\n{\n    int ret;\n    AVDeviceInfoList *device_list = NULL;\n\n    if (!fmt || !fmt->priv_class  || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))\n        return AVERROR(EINVAL);\n\n    printf(\"Auto-detected sources for %s:\\n\", fmt->name);\n    if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) {\n        printf(\"Cannot list sources: %s\\n\", av_err2str(ret));\n        goto fail;\n    }\n\n    print_device_list(device_list);\n\n  fail:\n    avdevice_free_list_devices(&device_list);\n    return ret;\n}\n\nstatic int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)\n{\n    int ret;\n    AVDeviceInfoList *device_list = NULL;\n\n    if (!fmt || !fmt->priv_class  || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))\n        return AVERROR(EINVAL);\n\n    printf(\"Auto-detected sinks for %s:\\n\", fmt->name);\n    if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) {\n        printf(\"Cannot list sinks: %s\\n\", av_err2str(ret));\n        goto fail;\n    }\n\n    print_device_list(device_list);\n\n  fail:\n    avdevice_free_list_devices(&device_list);\n    return ret;\n}\n\nstatic int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts)\n{\n    int ret;\n    if (arg) {\n        char *opts_str = NULL;\n        av_assert0(dev && opts);\n        *dev = av_strdup(arg);\n        if (!*dev)\n            return AVERROR(ENOMEM);\n        if ((opts_str = strchr(*dev, ','))) {\n            *(opts_str++) = '\\0';\n            if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, \"=\", \":\", 0)) < 0)) {\n                av_freep(dev);\n                return ret;\n            }\n        }\n    } else\n        printf(\"\\nDevice name is not provided.\\n\"\n                \"You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\\n\\n\");\n    return 0;\n}\n\nint show_sources(void *optctx, const char *opt, const char *arg)\n{\n    const AVInputFormat *fmt = NULL;\n    char *dev = NULL;\n    AVDictionary *opts = NULL;\n    int ret = 0;\n    int error_level = av_log_get_level();\n\n    av_log_set_level(AV_LOG_WARNING);\n\n    if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)\n        goto fail;\n\n    do {\n        fmt = av_input_audio_device_next(fmt);\n        if (fmt) {\n            if (!strcmp(fmt->name, \"lavfi\"))\n                continue; //it's pointless to probe lavfi\n            if (dev && !av_match_name(dev, fmt->name))\n                continue;\n            print_device_sources(fmt, opts);\n        }\n    } while (fmt);\n    do {\n        fmt = av_input_video_device_next(fmt);\n        if (fmt) {\n            if (dev && !av_match_name(dev, fmt->name))\n                continue;\n            print_device_sources(fmt, opts);\n        }\n    } while (fmt);\n  fail:\n    av_dict_free(&opts);\n    av_free(dev);\n    av_log_set_level(error_level);\n    return ret;\n}\n\nint show_sinks(void *optctx, const char *opt, const char *arg)\n{\n    const AVOutputFormat *fmt = NULL;\n    char *dev = NULL;\n    AVDictionary *opts = NULL;\n    int ret = 0;\n    int error_level = av_log_get_level();\n\n    av_log_set_level(AV_LOG_WARNING);\n\n    if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)\n        goto fail;\n\n    do {\n        fmt = av_output_audio_device_next(fmt);\n        if (fmt) {\n            if (dev && !av_match_name(dev, fmt->name))\n                continue;\n            print_device_sinks(fmt, opts);\n        }\n    } while (fmt);\n    do {\n        fmt = av_output_video_device_next(fmt);\n        if (fmt) {\n            if (dev && !av_match_name(dev, fmt->name))\n                continue;\n            print_device_sinks(fmt, opts);\n        }\n    } while (fmt);\n  fail:\n    av_dict_free(&opts);\n    av_free(dev);\n    av_log_set_level(error_level);\n    return ret;\n}\n#endif /* CONFIG_AVDEVICE */\n"
  },
  {
    "path": "src/fftools/opt_common.h",
    "content": "/*\n * Option handlers shared between the tools.\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifndef FFTOOLS_OPT_COMMON_H\n#define FFTOOLS_OPT_COMMON_H\n\n#include \"config.h\"\n\n#include \"cmdutils.h\"\n\n#if CONFIG_AVDEVICE\n/**\n * Print a listing containing autodetected sinks of the output device.\n * Device name with options may be passed as an argument to limit results.\n */\nint show_sinks(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing autodetected sources of the input device.\n * Device name with options may be passed as an argument to limit results.\n */\nint show_sources(void *optctx, const char *opt, const char *arg);\n#endif\n\n#if CONFIG_AVDEVICE\n#define CMDUTILS_COMMON_OPTIONS_AVDEVICE                                                                                \\\n    { \"sources\"    , OPT_EXIT | HAS_ARG, { .func_arg = show_sources },                                                  \\\n      \"list sources of the input device\", \"device\" },                                                                   \\\n    { \"sinks\"      , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks },                                                    \\\n      \"list sinks of the output device\", \"device\" },                                                                    \\\n\n#else\n#define CMDUTILS_COMMON_OPTIONS_AVDEVICE\n#endif\n\n/**\n * Print the license of the program to stdout. The license depends on\n * the license of the libraries compiled into the program.\n * This option processing function does not utilize the arguments.\n */\nint show_license(void *optctx, const char *opt, const char *arg);\n\n/**\n * Generic -h handler common to all fftools.\n */\nint show_help(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print the version of the program to stdout. The version message\n * depends on the current versions of the repository and of the libav*\n * libraries.\n * This option processing function does not utilize the arguments.\n */\nint show_version(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print the build configuration of the program to stdout. The contents\n * depend on the definition of FFMPEG_CONFIGURATION.\n * This option processing function does not utilize the arguments.\n */\nint show_buildconf(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the formats supported by the\n * program (including devices).\n * This option processing function does not utilize the arguments.\n */\nint show_formats(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the muxers supported by the\n * program (including devices).\n * This option processing function does not utilize the arguments.\n */\nint show_muxers(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the demuxer supported by the\n * program (including devices).\n * This option processing function does not utilize the arguments.\n */\nint show_demuxers(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the devices supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_devices(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the codecs supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_codecs(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the decoders supported by the\n * program.\n */\nint show_decoders(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the encoders supported by the\n * program.\n */\nint show_encoders(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the bit stream filters supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_bsfs(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the protocols supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_protocols(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the filters supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_filters(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the pixel formats supported by the\n * program.\n * This option processing function does not utilize the arguments.\n */\nint show_pix_fmts(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the standard channel layouts supported by\n * the program.\n * This option processing function does not utilize the arguments.\n */\nint show_layouts(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the sample formats supported by the\n * program.\n */\nint show_sample_fmts(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all supported stream dispositions.\n */\nint show_dispositions(void *optctx, const char *opt, const char *arg);\n\n/**\n * Print a listing containing all the color names and values recognized\n * by the program.\n */\nint show_colors(void *optctx, const char *opt, const char *arg);\n\n/**\n * Set the libav* libraries log level.\n */\nint opt_loglevel(void *optctx, const char *opt, const char *arg);\n\nint opt_report(void *optctx, const char *opt, const char *arg);\nint init_report(const char *env, FILE **file);\n\nint opt_max_alloc(void *optctx, const char *opt, const char *arg);\n\n/**\n * Override the cpuflags.\n */\nint opt_cpuflags(void *optctx, const char *opt, const char *arg);\n\n/**\n * Override the cpucount.\n */\nint opt_cpucount(void *optctx, const char *opt, const char *arg);\n\n#define CMDUTILS_COMMON_OPTIONS                                                                                         \\\n    { \"L\",           OPT_EXIT,             { .func_arg = show_license },     \"show license\" },                          \\\n    { \"h\",           OPT_EXIT,             { .func_arg = show_help },        \"show help\", \"topic\" },                    \\\n    { \"?\",           OPT_EXIT,             { .func_arg = show_help },        \"show help\", \"topic\" },                    \\\n    { \"help\",        OPT_EXIT,             { .func_arg = show_help },        \"show help\", \"topic\" },                    \\\n    { \"-help\",       OPT_EXIT,             { .func_arg = show_help },        \"show help\", \"topic\" },                    \\\n    { \"version\",     OPT_EXIT,             { .func_arg = show_version },     \"show version\" },                          \\\n    { \"buildconf\",   OPT_EXIT,             { .func_arg = show_buildconf },   \"show build configuration\" },              \\\n    { \"formats\",     OPT_EXIT,             { .func_arg = show_formats },     \"show available formats\" },                \\\n    { \"muxers\",      OPT_EXIT,             { .func_arg = show_muxers },      \"show available muxers\" },                 \\\n    { \"demuxers\",    OPT_EXIT,             { .func_arg = show_demuxers },    \"show available demuxers\" },               \\\n    { \"devices\",     OPT_EXIT,             { .func_arg = show_devices },     \"show available devices\" },                \\\n    { \"codecs\",      OPT_EXIT,             { .func_arg = show_codecs },      \"show available codecs\" },                 \\\n    { \"decoders\",    OPT_EXIT,             { .func_arg = show_decoders },    \"show available decoders\" },               \\\n    { \"encoders\",    OPT_EXIT,             { .func_arg = show_encoders },    \"show available encoders\" },               \\\n    { \"bsfs\",        OPT_EXIT,             { .func_arg = show_bsfs },        \"show available bit stream filters\" },     \\\n    { \"protocols\",   OPT_EXIT,             { .func_arg = show_protocols },   \"show available protocols\" },              \\\n    { \"filters\",     OPT_EXIT,             { .func_arg = show_filters },     \"show available filters\" },                \\\n    { \"pix_fmts\",    OPT_EXIT,             { .func_arg = show_pix_fmts },    \"show available pixel formats\" },          \\\n    { \"layouts\",     OPT_EXIT,             { .func_arg = show_layouts },     \"show standard channel layouts\" },         \\\n    { \"sample_fmts\", OPT_EXIT,             { .func_arg = show_sample_fmts }, \"show available audio sample formats\" },   \\\n    { \"dispositions\", OPT_EXIT,            { .func_arg = show_dispositions}, \"show available stream dispositions\" },    \\\n    { \"colors\",      OPT_EXIT,             { .func_arg = show_colors },      \"show available color names\" },            \\\n    { \"loglevel\",    HAS_ARG,              { .func_arg = opt_loglevel },     \"set logging level\", \"loglevel\" },         \\\n    { \"v\",           HAS_ARG,              { .func_arg = opt_loglevel },     \"set logging level\", \"loglevel\" },         \\\n    { \"report\",      0,                    { .func_arg = opt_report },       \"generate a report\" },                     \\\n    { \"max_alloc\",   HAS_ARG,              { .func_arg = opt_max_alloc },    \"set maximum size of a single allocated block\", \"bytes\" }, \\\n    { \"cpuflags\",    HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags },     \"force specific cpu flags\", \"flags\" },     \\\n    { \"cpucount\",    HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpucount },     \"force specific cpu count\", \"count\" },     \\\n    { \"hide_banner\", OPT_BOOL | OPT_EXPERT, {&hide_banner},     \"do not show program banner\", \"hide_banner\" },          \\\n    CMDUTILS_COMMON_OPTIONS_AVDEVICE                                                                                    \\\n\n#endif /* FFTOOLS_OPT_COMMON_H */\n"
  },
  {
    "path": "tests/.eslintrc.json",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"globals\": {\n    \"CORE_URL\": true,\n    \"FFMPEG_TYPE\": true,\n    \"FFmpegWASM\": true,\n    \"VIDEO_1S_MP4\": true,\n    \"b64ToUint8Array\": true,\n    \"createFFmpegCore\": true,\n    \"expect\": true\n  },\n  \"env\": {\n    \"node\": true,\n    \"commonjs\": true,\n    \"mocha\": true,\n    \"es2022\": true\n  }\n}\n"
  },
  {
    "path": "tests/ffmpeg-core-mt.test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"Cross-Origin-Opener-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Cross-Origin-Embedder-Policy\" content=\"require-corp\" />\n    <meta http-equiv=\"Cross-Origin-Resource-Policy\" content=\"cross-origin\" />\n    <meta http-equiv=\"Origin-Agent-Cluster\" content=\"?1\" />\n    <title>FFmpeg Unit Test</title>\n    <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\" />\n  </head>\n  <body>\n    <div id=\"mocha\"></div>\n    <script src=\"../node_modules/mocha/mocha.js\"></script>\n    <script src=\"../node_modules/chai/chai.js\"></script>\n    <script src=\"../packages/core-mt/dist/umd/ffmpeg-core.js\"></script>\n    <script src=\"./test-helper-browser.js\"></script>\n    <script type=\"text/javascript\">\n      window.FFMPEG_TYPE = \"mt\";\n    </script>\n    <script>\n      mocha.setup(\"bdd\");\n      mocha.timeout(60000);\n    </script>\n    <script src=\"./ffmpeg-core.test.js\"></script>\n    <script>\n      window.expect = chai.expect;\n      mocha.run();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/ffmpeg-core-st.test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"Cross-Origin-Opener-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Cross-Origin-Embedder-Policy\" content=\"require-corp\" />\n    <meta http-equiv=\"Cross-Origin-Resource-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Origin-Agent-Cluster\" content=\"?1\" />\n    <title>FFmpeg Unit Test</title>\n    <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\" />\n  </head>\n  <body>\n    <div id=\"mocha\"></div>\n    <script src=\"../node_modules/mocha/mocha.js\"></script>\n    <script src=\"../node_modules/chai/chai.js\"></script>\n    <script src=\"../packages/core/dist/umd/ffmpeg-core.js\"></script>\n    <script src=\"./test-helper-browser.js\"></script>\n    <script type=\"text/javascript\">\n      window.FFMPEG_TYPE = \"st\";\n    </script>\n    <script>\n      mocha.setup(\"bdd\");\n      mocha.timeout(60000);\n    </script>\n    <script src=\"./ffmpeg-core.test.js\"></script>\n    <script>\n      window.expect = chai.expect;\n      mocha.run();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/ffmpeg-core.test.js",
    "content": "let core;\n\nconst genName = (name) => `[ffmpeg-core][${FFMPEG_TYPE}] ${name}`;\n\nconst reset = () => {\n  core.reset();\n  core.setLogger(() => {});\n  core.setProgress(() => {});\n};\n\nbefore(async () => {\n  core = await createFFmpegCore();\n  core.FS.writeFile(\"video.mp4\", b64ToUint8Array(VIDEO_1S_MP4));\n});\n\ndescribe(genName(\"createFFmpeg()\"), () => {\n  it(\"should be OK\", () => {\n    expect(core).to.be.ok;\n  });\n});\n\ndescribe(genName(\"reset()\"), () => {\n  beforeEach(reset);\n\n  it(\"should exist\", () => {\n    expect(\"reset\" in core).to.be.true;\n  });\n  it(\"should reset ret and timeout\", () => {\n    core.ret = 1024;\n    core.timeout = 1024;\n\n    core.reset();\n\n    expect(core.ret).to.equal(-1);\n    expect(core.timeout).to.equal(-1);\n  });\n});\n\ndescribe(genName(\"exec()\"), () => {\n  beforeEach(reset);\n\n  it(\"should exist\", () => {\n    expect(\"exec\" in core).to.be.true;\n  });\n\n  it(\"should output help\", () => {\n    expect(core.exec(\"-h\")).to.equal(0);\n  });\n\n  it(\"should transcode\", () => {\n    expect(core.exec(\"-i\", \"video.mp4\", \"video.avi\")).to.equal(0);\n    const out = core.FS.readFile(\"video.avi\");\n    expect(out.length).to.not.equal(0);\n    core.FS.unlink(\"video.avi\");\n  });\n});\n\ndescribe(genName(\"setTimeout()\"), () => {\n  beforeEach(reset);\n\n  it(\"should exist\", () => {\n    expect(\"setTimeout\" in core).to.be.true;\n  });\n\n  it(\"should timeout\", () => {\n    core.setTimeout(1); // timeout after 1ms\n    expect(core.exec(\"-i\", \"video.mp4\", \"video.avi\")).to.equal(1);\n  });\n});\n\ndescribe(genName(\"setLogger()\"), () => {\n  beforeEach(reset);\n\n  it(\"should exist\", () => {\n    expect(\"setLogger\" in core).to.be.true;\n  });\n\n  it(\"should handle logs\", () => {\n    const logs = [];\n    core.setLogger(({ message }) => logs.push(message));\n    core.exec(\"-h\");\n    expect(logs.length).to.not.equal(0);\n  });\n});\n\ndescribe(genName(\"setProgress()\"), () => {\n  beforeEach(reset);\n\n  it(\"should exist\", () => {\n    expect(\"setProgress\" in core).to.be.true;\n  });\n\n  it(\"should handle progress\", () => {\n    let progress = 0;\n    core.setProgress(({ progress: _progress }) => (progress = _progress));\n    expect(core.exec(\"-i\", \"video.mp4\", \"video.avi\")).to.equal(0);\n    expect(progress).to.equal(1);\n    core.FS.unlink(\"video.avi\");\n  });\n});\n"
  },
  {
    "path": "tests/ffmpeg-mt.test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"Cross-Origin-Opener-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Cross-Origin-Embedder-Policy\" content=\"require-corp\" />\n    <meta http-equiv=\"Cross-Origin-Resource-Policy\" content=\"cross-origin\" />\n    <meta http-equiv=\"Origin-Agent-Cluster\" content=\"?1\" />\n    <title>FFmpeg Unit Test</title>\n    <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\" />\n  </head>\n  <body>\n    <div id=\"mocha\"></div>\n    <script src=\"../node_modules/mocha/mocha.js\"></script>\n    <script src=\"../node_modules/chai/chai.js\"></script>\n    <script src=\"../packages/ffmpeg/dist/umd/ffmpeg.js\"></script>\n    <script src=\"./test-helper-browser.js\"></script>\n    <script type=\"text/javascript\">\n      window.FFMPEG_TYPE = \"mt\";\n      window.CORE_URL =\n        \"http://localhost:3000/packages/core-mt/dist/umd/ffmpeg-core.js\";\n    </script>\n    <script>\n      mocha.setup(\"bdd\");\n      mocha.timeout(60000);\n    </script>\n    <script src=\"./ffmpeg.test.js\"></script>\n    <script>\n      window.expect = chai.expect;\n      mocha.run();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/ffmpeg-st.test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta http-equiv=\"Cross-Origin-Opener-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Cross-Origin-Embedder-Policy\" content=\"require-corp\" />\n    <meta http-equiv=\"Cross-Origin-Resource-Policy\" content=\"same-origin\" />\n    <meta http-equiv=\"Origin-Agent-Cluster\" content=\"?1\" />\n    <title>FFmpeg Unit Test</title>\n    <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\" />\n  </head>\n  <body>\n    <div id=\"mocha\"></div>\n    <script src=\"../node_modules/mocha/mocha.js\"></script>\n    <script src=\"../node_modules/chai/chai.js\"></script>\n    <script src=\"../packages/ffmpeg/dist/umd/ffmpeg.js\"></script>\n    <script src=\"./test-helper-browser.js\"></script>\n    <script type=\"text/javascript\">\n      window.FFMPEG_TYPE = \"st\";\n      window.CORE_URL =\n        \"http://localhost:3000/packages/core/dist/umd/ffmpeg-core.js\";\n    </script>\n    <script>\n      mocha.setup(\"bdd\");\n      mocha.timeout(60000);\n    </script>\n    <script src=\"./ffmpeg.test.js\"></script>\n    <script>\n      window.expect = chai.expect;\n      mocha.run();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/ffmpeg.test.js",
    "content": "const { FFmpeg } = window.FFmpegWASM;\n\nconst genName = (name) => `[ffmpeg][${FFMPEG_TYPE}] ${name}`;\n\nconst createFFmpeg = async () => {\n  const ffmpeg = new FFmpeg();\n  await ffmpeg.load({\n    coreURL: CORE_URL,\n    thread: FFMPEG_TYPE === \"mt\",\n  });\n  return ffmpeg;\n};\n\ndescribe(genName(\"new FFmpeg()\"), () => {\n  it(\"should be OK\", () => {\n    expect(new FFmpeg()).to.be.ok;\n  });\n});\n\ndescribe(\n  genName(\n    \"FFmpeg directory APIs (createDir(), listDir(), deleteDir(), rename())\"\n  ),\n  function () {\n    let ffmpeg;\n\n    before(async () => {\n      ffmpeg = await createFFmpeg();\n    });\n\n    after(() => {\n      ffmpeg.terminate();\n    });\n\n    it(\"should list root dir\", async () => {\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files).to.have.lengthOf(6);\n    });\n\n    it(\"should create a dir\", async () => {\n      await ffmpeg.createDir(\"/dir1\");\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files.map(({ name }) => name)).to.include(\"dir1\");\n    });\n\n    it(\"should delete a dir\", async () => {\n      await ffmpeg.createDir(\"/dir2\");\n      await ffmpeg.deleteDir(\"/dir2\");\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files.map(({ name }) => name)).to.not.include(\"dir2\");\n    });\n\n    it(\"should rename a dir\", async () => {\n      await ffmpeg.createDir(\"/dir3\");\n      await ffmpeg.rename(\"/dir3\", \"/dir4\");\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files.map(({ name }) => name)).to.not.include(\"dir3\");\n      expect(files.map(({ name }) => name)).to.include(\"dir4\");\n    });\n  }\n);\n\ndescribe(\n  genName(\n    \"FFmpeg files APIs (readFile(), writeFile(), deleteFile(), rename())\"\n  ),\n  function () {\n    let ffmpeg;\n\n    before(async () => {\n      ffmpeg = await createFFmpeg();\n    });\n\n    after(() => {\n      ffmpeg.terminate();\n    });\n\n    it(\"should write/read a text file\", async () => {\n      const text = \"foo\";\n      await ffmpeg.writeFile(\"/file1\", text);\n      const data = await ffmpeg.readFile(\"/file1\", \"utf8\");\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files.map(({ name }) => name)).to.include(\"file1\");\n      expect(data).to.equal(text);\n    });\n\n    it(\"should write a binary file\", async () => {\n      const bin = [1, 2, 3];\n      await ffmpeg.writeFile(\"/file2\", Uint8Array.from(bin));\n      const data = await ffmpeg.readFile(\"/file2\");\n      const files = await ffmpeg.listDir(\"/\");\n      expect(files.map(({ name }) => name)).to.include(\"file2\");\n      expect(data).to.deep.equal(Uint8Array.from(bin));\n    });\n  }\n);\n\ndescribe(genName(\"FFmpeg.exec()\"), function () {\n  let ffmpeg;\n\n  before(async () => {\n    ffmpeg = await createFFmpeg();\n    await ffmpeg.writeFile(\"video.mp4\", b64ToUint8Array(VIDEO_1S_MP4));\n  });\n\n  after(() => {\n    ffmpeg.terminate();\n  });\n\n  it(\"should output help with exit code 0\", async () => {\n    let m;\n    const listener = ({ message }) => {\n      m = message;\n    };\n    ffmpeg.on(\"log\", listener);\n    const ret = await ffmpeg.exec([\"-h\"]);\n    expect(ret).to.equal(0);\n    expect(m).to.be.a(\"string\");\n    ffmpeg.off(\"log\", listener);\n  });\n\n  it(\"should transcode mp4 to avi\", async () => {\n    let p;\n    const listener = ({ progress }) => {\n      p = progress;\n    };\n    ffmpeg.on(\"progress\", listener);\n    const ret = await ffmpeg.exec([\"-i\", \"video.mp4\", \"video.avi\"]);\n    expect(ret).to.equal(0);\n    expect(p).to.equal(1);\n    ffmpeg.off(\"progress\", listener);\n  });\n\n  it(\"should stop if timeout\", async () => {\n    const ret = await ffmpeg.exec([\"-i\", \"video.mp4\", \"video.avi\"], 1);\n    expect(ret).to.equal(1);\n  });\n\n  it(\"should abort\", () => {\n    const controller = new AbortController();\n    const { signal } = controller;\n\n    const promise = ffmpeg.exec([\"-i\", \"video.mp4\", \"video.avi\"], undefined, {\n      signal,\n    });\n    controller.abort();\n\n    return promise.catch((err) => {\n      expect(err.name).to.equal(\"AbortError\");\n    });\n  });\n});\n"
  },
  {
    "path": "tests/index.html",
    "content": "<html>\n  <body>\n    <h3>Quick Test</h3>\n    <video id=\"output-video\" controls></video><br/>\n    <input type=\"file\" id=\"uploader\">\n    <p id=\"message\"></p>\n    <script type=\"module\">\n      import { FFmpeg } from \"/packages/ffmpeg/dist/esm/index.js\";\n      import { fetchFile } from \"/packages/util/dist/esm/index.js\";\n      let ffmpeg = null;\n\n      const transcode = async ({ target: { files } }) => {\n        const message = document.getElementById('message');\n        if (ffmpeg === null) {\n          ffmpeg = new FFmpeg();\n          ffmpeg.on(\"log\", ({ message }) => {\n            console.log(message);\n          })\n          ffmpeg.on(\"progress\", ({ progress }) => {\n            message.innerHTML = `${progress * 100} %`;\n          });\n          await ffmpeg.load({\n            coreURL: \"/packages/core/dist/esm/ffmpeg-core.js\",\n          });\n        }\n        const { name } = files[0];\n        await ffmpeg.writeFile(name, await fetchFile(files[0]));\n        message.innerHTML = 'Start transcoding';\n        await ffmpeg.exec(['-i', name,  'output.mp4']);\n        message.innerHTML = 'Complete transcoding';\n        const data = await ffmpeg.readFile('output.mp4');\n\n        const video = document.getElementById('output-video');\n        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));\n      }\n      const elm = document.getElementById('uploader');\n      elm.addEventListener('change', transcode);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/test-helper-browser.js",
    "content": "const VIDEO_1S_MP4 =\n  \"AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACNVtZGF0AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2NCByMzA5NSBiYWVlNDAwIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAyMiAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAWGWIhAF/VX4sk7I8JNZmcVHQGdQU4nCgQu3bAPr3Ssqud5vlQU8WOoVflLYchsLrqUetFXfqLXphmtuS3mHrApyfX5v/uDan0K7q3tqbCPqu5Eh0777mj+EAAAAIQZoibE3/L6AAAAAIAZ5BeRX/q4EAAAALQZpDPCGTKYTfL6AAAAAkQZpkSeEPJlMCI/+6WXP8TS428XZ4MAoWt7Rbefgh+p7Ovza9AAAASkGahknhDyZTBRE8R/DOlNnJYnp2ZKmOads4/A+TeG7SJ61nL/yX+79a54dCz54ND/oxgDUfsdL9bYerAkJ4S7b/QuVDCFi7an/5AAAAGAGepWpEf+ojd6G9/p6T+sKI3FWRE1tf8QAAAE5BmqhL4QhDyHwHkDNAeQNQFP/eTAsfmPZWDJwHKv00/193JNLDX9vEU5S8+AaSauTJGX9XjcYc20A53pP0ZfGVkgg4kzF2MCXUqSi1f4EAAAAXAZ7HakR/6Q+F8S3/WTc486ZsurQLbfAAAAA1QZrMSeEPJlMD/9KZNRNNOhbOBKQ6q4LrGP8NYrF8f4TzVOC+3z8gVFpNSWA8HY7ZPYryn/AAAAAnQZ7qRRE8n+sSXOiLwLBw9weW3k6+acj0yJPgiQln8XrThIj6CyOPAAAAHwGfCXREf+4iIDcXIhD/KfFLoLrIVDZw8GXWDUFYVbgAAAAdAZ8LakR/xdSBAjkaWxEt7HVcbi1ex+ri+ibT/4AAAAAxQZsOSahBaJlMFP9UzN6CI9q/wYhzQKYMAWVleRV72AaocIbTHdlBM+eFTglJgGksHwAAABoBny1qRH/OO1eCiglHLfJ93eMk9luL7iyK8QAAAD1Bmy9L4QhClIIwHskB7QC/vUfq8JD6a+GCczONvLjIPVA1B4cHt7eiuYJ8cfL+rcQTjiNldEjrMyQYyr/9AAAANEGbUknhDomUwP+Fqlmop+IF4l1MYxqUCGikoXe/XTWkPedc/8doqY7xtVeF1Zy741A4dwMAAAAbQZ9wRRE838dFFLcEQs657QlL6G+zvbqwQWnwAAAAJAGfkWpEf7ns5Hrc53S3CaJ6WjIBr2DJNg6qTQDvnZlI5gZLIQAAADJBm5RJqEFomUwU/3Qx1esB400Ds1pe8D3sMqSpOWZ1tHatL6L4lI+MoT+wBNGKQBUVngAAABMBn7NqRH/No+NYmNfaNLubP9oMAAAAKkGbtUnhClJlMD/ShPuBwUDVsIz2jOh5OyGUlGvY4riclbK8jgmoEZSafwAAADNBm9ZJ4Q6JlMD/i/vD+WfvtC+Wu2zd/OfTklr49N8KzEP0Vr8S1rMQx6A7tSrmpYRM1+AAAAAvQZv3SeEPJlMD/8wT+KHlxm5cqF8tasMZ28tXFl5IuX1CE1TlBQ7H8bPBD/apmsEAAAA2QZoYSeEPJlMCv53NDIJ+vJ5Zfu0dtAuaNhkbkiknlRQIAwTuVgz8t/38jTdAUohcv7nJ4o1BAAAAM0GaOUnhDyZTAr+hCi1pMEN2Jl+DeW139WAkpJBW182bVMDfpNtO7zonfep+/w+EoU6HLgAAADdBmlpJ4Q8mUwJP9p8kGycclsD2wk/sD+ql+ELVaMal66VEx88hAH0I+6Q/3GPw5360uuCZ2xKdAAAAQ0Gae0vhCEPIfASQlASQsAm/xWRF7wudZxflIF/rQCURssh2dulABXXzZZOHvT4D/0chLuuHy1OS/KQ4rZydwlQDF+AAAAA0QZqcSeEPJlMCK//8ceDjqx4KCAM38JzwlNQgqy9TxT477rIXurZ/qevdCvTQrUbszwL2/wAAADJBmr1J4Q8mUwIr/8nMU86WdSr6iHCve9IX3hPJJhZQa/TjXHI5SNVnGlvAo63Wl/0TWwAAACxBmt5J4Q8mUwIz/8Gnomo7mBKn9lR8lfWgZv7NfoScldpOlvNJYaZATJGl8AAAACpBmuBJ4Q8mUwURPCH/96ZbC9HH/X/m6Q7/SUGz71k5KVtG+d2cIF4n4fAAAAALAZ8fakKf8sQOH6cAAAAbQZsCSeEPJlMFPC3/+OcjK4527KNuTJhYyizWAAAACAGfIWpC38GBAAAEdW1vb3YAAABsbXZoZAAAAAAAAAAAAAAAAAAAA+gAAAPoAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAOfdHJhawAAAFx0a2hkAAAAAwAAAAAAAAAAAAAAAQAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAgAAAAHgAAAAAAJGVkdHMAAAAcZWxzdAAAAAAAAAABAAAD6AAABAAAAQAAAAADF21kaWEAAAAgbWRoZAAAAAAAAAAAAAAAAAAARgAAAEYAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAsJtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAKCc3RibAAAAK5zdHNkAAAAAAAAAAEAAACeYXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAgAB4ASAAAAEgAAAAAAAAAARVMYXZjNTkuMzcuMTAwIGxpYngyNjQAAAAAAAAAAAAAABj//wAAADRhdmNDAWQACv/hABdnZAAKrNlJfqEAAAMAAQAAAwBGDxIllgEABmjr48siwP34+AAAAAAUYnRydAAAAAAAAEZoAABGaAAAABhzdHRzAAAAAAAAAAEAAAAjAAACAAAAABRzdHNzAAAAAAAAAAEAAAABAAAA0GN0dHMAAAAAAAAAGAAAAAEAAAQAAAAAAQAABgAAAAABAAACAAAAAAIAAAQAAAAAAQAABgAAAAABAAACAAAAAAEAAAYAAAAAAQAAAgAAAAABAAAKAAAAAAEAAAQAAAAAAQAAAAAAAAABAAACAAAAAAEAAAYAAAAAAQAAAgAAAAABAAAEAAAAAAEAAAgAAAAAAgAAAgAAAAABAAAGAAAAAAEAAAIAAAAACgAABAAAAAABAAAGAAAAAAEAAAIAAAAAAQAABgAAAAABAAACAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAIwAAAAEAAACgc3RzegAAAAAAAAAAAAAAIwAAAw4AAAAMAAAADAAAAA8AAAAoAAAATgAAABwAAABSAAAAGwAAADkAAAArAAAAIwAAACEAAAA1AAAAHgAAAEEAAAA4AAAAHwAAACgAAAA2AAAAFwAAAC4AAAA3AAAAMwAAADoAAAA3AAAAOwAAAEcAAAA4AAAANgAAADAAAAAuAAAADwAAAB8AAAAMAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU5LjI3LjEwMA==\";\n\nconst b64ToUint8Array = (b64) => {\n  const bin = atob(b64);\n  const len = bin.length;\n  const bytes = new Uint8Array(len);\n  for (let i = 0; i < len; i++) {\n    bytes[i] = bin.charCodeAt(i);\n  }\n  return bytes;\n};\n\nif (typeof module !== \"undefined\") {\n  module.exports = {\n    VIDEO_1S_MP4,\n    b64ToUint8Array,\n  };\n}\n"
  },
  {
    "path": "tests/test-helper-mt.js",
    "content": "const chai = require(\"chai\");\nconst browser = require(\"./test-helper-browser\");\n\nglobal.expect = chai.expect;\nglobal.createFFmpegCore = require(\"../packages/core-mt\");\nglobal.atob = require(\"./util\").atob;\nglobal.FFMPEG_TYPE = \"mt\";\n\nObject.keys(browser).forEach((key) => {\n  global[key] = browser[key];\n});\n"
  },
  {
    "path": "tests/test-helper-st.js",
    "content": "const chai = require(\"chai\");\nconst browser = require(\"./test-helper-browser\");\n\nglobal.expect = chai.expect;\nglobal.createFFmpegCore = require(\"../packages/core\");\nglobal.atob = require(\"./util\").atob;\nglobal.FFMPEG_TYPE = \"st\";\n\nObject.keys(browser).forEach((key) => {\n  global[key] = browser[key];\n});\n"
  },
  {
    "path": "tests/util.js",
    "content": "exports.atob = (b64) => Buffer.from(b64, \"base64\").toString(\"binary\");\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    /* Visit https://aka.ms/tsconfig to read more about this file */\n\n    /* Projects */\n    // \"incremental\": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */\n    // \"composite\": true,                                [> Enable constraints that allow a TypeScript project to be used with project references. <]\n    // \"tsBuildInfoFile\": \"./.tsbuildinfo\",              /* Specify the path to .tsbuildinfo incremental compilation file. */\n    // \"disableSourceOfProjectReferenceRedirect\": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */\n    // \"disableSolutionSearching\": true,                 /* Opt a project out of multi-project reference checking when editing. */\n    // \"disableReferencedProjectLoad\": true,             /* Reduce the number of projects loaded automatically by TypeScript. */\n\n    /* Language and Environment */\n    \"target\": \"es2016\",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */\n    // \"lib\": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */\n    // \"jsx\": \"preserve\",                                /* Specify what JSX code is generated. */\n    // \"experimentalDecorators\": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */\n    // \"emitDecoratorMetadata\": true,                    /* Emit design-type metadata for decorated declarations in source files. */\n    // \"jsxFactory\": \"\",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */\n    // \"jsxFragmentFactory\": \"\",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */\n    // \"jsxImportSource\": \"\",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */\n    // \"reactNamespace\": \"\",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */\n    // \"noLib\": true,                                    /* Disable including any library files, including the default lib.d.ts. */\n    // \"useDefineForClassFields\": true,                  /* Emit ECMAScript-standard-compliant class fields. */\n    // \"moduleDetection\": \"auto\",                        /* Control what method is used to detect module-format JS files. */\n\n    /* Modules */\n    \"module\": \"commonjs\",                                /* Specify what module code is generated. */\n    // \"rootDir\": \"./\",                                  /* Specify the root folder within your source files. */\n    \"moduleResolution\": \"node\",                       /* Specify how TypeScript looks up a file from a given module specifier. */\n    \"baseUrl\": \"./\",                                  /* Specify the base directory to resolve non-relative module names. */\n    \"paths\": {\n      \"@ffmpeg/*\": [\"packages/*\"]\n    },                                      /* Specify a set of entries that re-map imports to additional lookup locations. */\n    // \"rootDirs\": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */\n    // \"typeRoots\": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */\n    // \"types\": [],                                      /* Specify type package names to be included without being referenced in a source file. */\n    // \"allowUmdGlobalAccess\": true,                     /* Allow accessing UMD globals from modules. */\n    // \"moduleSuffixes\": [],                             /* List of file name suffixes to search when resolving a module. */\n    // \"resolveJsonModule\": true,                        /* Enable importing .json files. */\n    // \"noResolve\": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */\n\n    /* JavaScript Support */\n    // \"allowJs\": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */\n    // \"checkJs\": true,                                  /* Enable error reporting in type-checked JavaScript files. */\n    // \"maxNodeModuleJsDepth\": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */\n\n    /* Emit */\n    // \"declaration\": true,                              [> Generate .d.ts files from TypeScript and JavaScript files in your project. <]\n    // \"declarationMap\": true,                           /* Create sourcemaps for d.ts files. */\n    // \"emitDeclarationOnly\": true,                      /* Only output d.ts files and not JavaScript files. */\n    // \"sourceMap\": true,                                /* Create source map files for emitted JavaScript files. */\n    // \"outFile\": \"./\",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */\n    // \"outDir\": \"./\",                                   /* Specify an output folder for all emitted files. */\n    // \"removeComments\": true,                           /* Disable emitting comments. */\n    // \"noEmit\": true,                                   /* Disable emitting files from a compilation. */\n    // \"importHelpers\": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */\n    // \"importsNotUsedAsValues\": \"remove\",               /* Specify emit/checking behavior for imports that are only used for types. */\n    // \"downlevelIteration\": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */\n    // \"sourceRoot\": \"\",                                 /* Specify the root path for debuggers to find the reference source code. */\n    // \"mapRoot\": \"\",                                    /* Specify the location where debugger should locate map files instead of generated locations. */\n    // \"inlineSourceMap\": true,                          /* Include sourcemap files inside the emitted JavaScript. */\n    // \"inlineSources\": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */\n    // \"emitBOM\": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */\n    // \"newLine\": \"crlf\",                                /* Set the newline character for emitting files. */\n    // \"stripInternal\": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */\n    // \"noEmitHelpers\": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */\n    // \"noEmitOnError\": true,                            /* Disable emitting files if any type checking errors are reported. */\n    // \"preserveConstEnums\": true,                       /* Disable erasing 'const enum' declarations in generated code. */\n    // \"declarationDir\": \"./\",                           /* Specify the output directory for generated declaration files. */\n    // \"preserveValueImports\": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */\n\n    /* Interop Constraints */\n    // \"isolatedModules\": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */\n    // \"allowSyntheticDefaultImports\": true,             /* Allow 'import x from y' when a module doesn't have a default export. */\n    \"esModuleInterop\": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */\n    // \"preserveSymlinks\": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */\n    \"forceConsistentCasingInFileNames\": true,            /* Ensure that casing is correct in imports. */\n\n    /* Type Checking */\n    \"strict\": true,                                      /* Enable all strict type-checking options. */\n    // \"noImplicitAny\": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */\n    // \"strictNullChecks\": true,                         /* When type checking, take into account 'null' and 'undefined'. */\n    // \"strictFunctionTypes\": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */\n    // \"strictBindCallApply\": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */\n    // \"strictPropertyInitialization\": true,             /* Check for class properties that are declared but not set in the constructor. */\n    // \"noImplicitThis\": true,                           /* Enable error reporting when 'this' is given the type 'any'. */\n    // \"useUnknownInCatchVariables\": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */\n    // \"alwaysStrict\": true,                             /* Ensure 'use strict' is always emitted. */\n    // \"noUnusedLocals\": true,                           /* Enable error reporting when local variables aren't read. */\n    // \"noUnusedParameters\": true,                       /* Raise an error when a function parameter isn't read. */\n    // \"exactOptionalPropertyTypes\": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */\n    // \"noImplicitReturns\": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */\n    // \"noFallthroughCasesInSwitch\": true,               /* Enable error reporting for fallthrough cases in switch statements. */\n    // \"noUncheckedIndexedAccess\": true,                 /* Add 'undefined' to a type when accessed using an index. */\n    // \"noImplicitOverride\": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */\n    // \"noPropertyAccessFromIndexSignature\": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */\n    // \"allowUnusedLabels\": true,                        /* Disable error reporting for unused labels. */\n    // \"allowUnreachableCode\": true,                     /* Disable error reporting for unreachable code. */\n\n    /* Completeness */\n    // \"skipDefaultLibCheck\": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */\n    \"skipLibCheck\": true                                 /* Skip type checking all .d.ts files. */\n  }\n}\n"
  }
]