{"id":25623421,"url":"https://github.com/yu2924/jucemediafoundation","last_synced_at":"2025-08-26T14:03:03.680Z","repository":{"id":245066885,"uuid":"817158289","full_name":"yu2924/JuceMediaFoundation","owner":"yu2924","description":"a JUCE \u0026 Media Foundation experiment","archived":false,"fork":false,"pushed_at":"2024-06-23T08:58:05.000Z","size":67,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-06-23T09:52:42.189Z","etag":null,"topics":["audio-codec","experiment","juce","mediafoundation"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yu2924.png","metadata":{"files":{"readme":"README-ja.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-19T06:25:41.000Z","updated_at":"2024-06-23T08:58:08.000Z","dependencies_parsed_at":"2024-06-19T14:14:53.024Z","dependency_job_id":null,"html_url":"https://github.com/yu2924/JuceMediaFoundation","commit_stats":null,"previous_names":["yu2924/jucemediafoundation"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yu2924%2FJuceMediaFoundation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yu2924%2FJuceMediaFoundation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yu2924%2FJuceMediaFoundation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yu2924%2FJuceMediaFoundation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yu2924","download_url":"https://codeload.github.com/yu2924/JuceMediaFoundation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240170060,"owners_count":19759141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio-codec","experiment","juce","mediafoundation"],"created_at":"2025-02-22T11:37:58.353Z","updated_at":"2025-02-22T11:37:58.921Z","avatar_url":"https://github.com/yu2924.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JuceMediaFoundation\n\n## 目次\n- [1. 動機と目的](#1-動機と目的)\n- [2. 実験: TestMFSourceReader](#2-実験-testmfsourcereader)\n  - [2.1. メディア長さの不一致](#21-メディア長さの不一致)\n  - [2.2. 不連続なタイムスタンプ](#22-不連続なタイムスタンプ)\n  - [2.3. 不適当なシーク](#23-不適当なシーク)\n  - [2.4. 実験の結果](#24-実験の結果)\n- [3. 実用的な実装: JuceMediaFoundation](#3-実用的な実装-jucemediafoundation)\n- [4. 結び](#4-結び)\n- [Written by](#written-by)\n- [License](#license)\n\n## 1. 動機と目的\n\nJUCEにはWindowsMediaAudioFormatクラスが用意されている。これはWindows Media Format SDK (WMFSDK)を利用しており、Windowsプラットフォームがサポートする多くのメディアフォーマットを扱うことが出来るが、Windows 10以降に追加された新しいコーデックはMedia Foundation Transform (MFT)として提供されており、WMFSDKではサポート出来ない。そこで、より新しいMedia Foundation APIを使った自前のAudioFormatクラスの実装を試みた。  \nAudioFormatの形にするためには、サンプル精度でのシーク能力が必要になるが、いくつかの問題に突き当たった。\n\n- 不正確なメディア長さ\n- 不正確なタイムスタンプ\n- 不適当なシーク\n\nこれらの挙動はメディアフォーマットによって異なるようだった。そこで、実験により上手く動作するメディアフォーマットを探求し、最終的に実用的なMediaFoundationAudioFormatクラスを実装した。\n\n## 2. 実験: TestMFSourceReader\n\nこの小さなプログラムはMedia Foundation APIの提供するMFSourceReaderを使ってメディアファイルを開き、その挙動を検証する。\n\n- メディアファイルを開いて、フォーマットやメディア長さを正しく取得できるか\n- サンプルのタイムスタンプが正しく取得できているか\n- シーク後の実際の位置は適正か\n\n### 2.1. メディア長さの不一致\n\nプレゼンテーション属性から取得したメディア長さと、読み出したサンプル数の合計が食い違うことがある。\n\n![length mismatch](media/length-mismatch.png)\n\n### 2.2. 不連続なタイムスタンプ\n\n連続してサンプルバッファを読み出したとき、取得したタイムスタンプが不連続になることがある。\n\n![discontinuity](media/discontinuity.png)\n\n### 2.3. 不適当なシーク\n\nMFSourceReaderはサンプル精度のシークを保証していないので、シークした後に望みの位置にストリームを進める必要がある。そのため、ストリームをシークしたとき実際の位置が指定した位置と同じかそれより前であることが望ましい。しかし実際にはそれよりも後になることがある。\n\n![improper seeking](media/improper-seek.png)\n\n### 2.4. 実験の結果\n\n|media format|length mismatch|discontinuity|improper seeking|\n|-|-:|-:|-:|\n|FLAC|😡|😊|😡|\n|AAC (.m4a, .mp4)|😊|😊|😊|\n|ALAC (.m4a)|😡|😡|😡|\n|MP3|😡|😡|😊|\n|WAV|😊|😊|😊|\n\nAAC (m4a, mp4)での動作は良好であった。その他のフォーマットはJUCEに既にあるクラスに任せるのが良さそうだ。\n\n## 3. 実用的な実装: JuceMediaFoundation\n\n実験を踏まえて、より実用的なMediaFoundationAudioFormatクラスを試作して単純なアプリケーションに組み込んだ。このアプリケーションはJUCE 7.0.8を利用して作成され、波形サムネイルとプレイバックの為にそれぞれAudioFormatReaderクラスを利用する。  MediaFoundationAudioFormatクラスにはAAC (.m4a, .mp4)フォーマットだけを担当させるようにしたが、同じ.m4a拡張子を持つALACフォーマットではうまく動作しないことがわかっている。\n\n![JuceMediaFoundation](media/JuceMediaFoundation.png)\n\n## 4. 結び\n\n労多くして功少なし。\n\n## Written by\n\n[yu2924](https://twitter.com/yu2924)\n\n## License\n\nCC0 1.0 Universal\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyu2924%2Fjucemediafoundation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyu2924%2Fjucemediafoundation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyu2924%2Fjucemediafoundation/lists"}