{"id":11018116,"url":"https://github.com/encoding-ninja/per-title-analysis","last_synced_at":"2025-09-19T17:32:15.504Z","repository":{"id":201746502,"uuid":"115124089","full_name":"encoding-ninja/per-title-analysis","owner":"encoding-ninja","description":"Analysis provider for adapting your OTT bitrate ladder","archived":false,"fork":false,"pushed_at":"2022-11-14T14:14:08.000Z","size":33,"stargazers_count":56,"open_issues_count":2,"forks_count":19,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-09-20T14:30:57.998Z","etag":null,"topics":["encoding","optimization","per-title","video","video-encoding","video-quality"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/encoding-ninja.png","metadata":{"files":{"readme":"README.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}},"created_at":"2017-12-22T14:47:23.000Z","updated_at":"2024-08-17T12:31:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"287e7725-7a42-48e6-8920-6b011461337a","html_url":"https://github.com/encoding-ninja/per-title-analysis","commit_stats":null,"previous_names":["antoinehng/per-title-analysis","encoding-ninja/per-title-analysis"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encoding-ninja%2Fper-title-analysis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encoding-ninja%2Fper-title-analysis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encoding-ninja%2Fper-title-analysis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/encoding-ninja%2Fper-title-analysis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/encoding-ninja","download_url":"https://codeload.github.com/encoding-ninja/per-title-analysis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233582316,"owners_count":18697825,"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":["encoding","optimization","per-title","video","video-encoding","video-quality"],"created_at":"2024-06-11T11:14:12.324Z","updated_at":"2025-09-19T17:32:10.192Z","avatar_url":"https://github.com/encoding-ninja.png","language":"Python","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# Per-Title Analysis\n*This a python package providing tools for optimizing your over-the-top bitrate ladder per each video you need to encode.*\n\n\n## How does it work?\nYou can configure a template encoding ladder with constraints (min/max bitrate) that will be respected for the output optimal ladder.\nYou also have the control over analysis parameters (based on CRF encoding or multiple bitrate encodings with video quality metric assessments).\n\nThe CRF Analyzer\nThis analyzer calculates an optimal bitrate for the higher profile.\nOther profiles are declined top to bottom from the initial gap between each profiles of the template ladder.\n\nThe Metric Analyzer\nThis analyzer encodes multiple bitrates for each profile in the template ladder (from min to max, respecting a bitrate step defined by the user)\nIt then calculates video quality metrics for each of these encodings (only ssim or psnr for now).\nThe final optimized ladder will be constructed choosing for the best quality/bitrate ratio (similar to Netflix).\n\n### The template encoding ladder\nIt is composed of multiple encoding profile object.\nEach encoding profile is defined by those attributes:\n- __width__ (int): Video definition width\n- __height__ (int): Video definition height\n- __bitrate_default__ (int): This should be the bitrate of your static encoding ladder\n- __bitrate_min__ (int): This is the minimal bitrate you set for this profile in the output optimized encoding ladder\n- __bitrate_max__ (int): This is the maximal bitrate you set for this profile in the output optimized encoding ladder\n- __required__ (bool): Indicates if you authorize the script to remove this profile if considered not useful after optimization (conditions for this to happen are explained after)\n- __bitrate_factor__ (float): this is a private attribute calculated after initialization of the template encoding ladder \n\n##### See this template example\n| width | height | bitrate_default | bitrate_min | bitrate_max | required |\n| --- | --- | --- | --- | --- | --- |\n| *in pixels* | *in pixels* | *in bits per second* | *in bits per second* | *in bits per second* | *bool* |\n| 1920 | 1080 | 4500000 | 2000000 | 6000000 | True |\n| 1280 | 720 | 3400000 | 1300000 | 4500000 | True |\n| 960 | 540 | 2100000 | 700000 | 3000000 | True |\n| 640 | 360 | 1100000 | 300000 | 2000000 | True |\n| 480 | 270 | 750000 | 300000 | 900000 | False |\n| 480 | 270 | 300000 | 150000 | 500000 | True |\n##### What does it imply? *(soon)*\n\n#### In depth: *(soon)*\n- How to choose the analysis parameters\n- What is the multiple part analysis\n- How is the weighted average bitrate calculated\n- Documentation for the JSON ouput\n\n___\n\n##  Installation:\nThis is package requires at least Python 3.4.\n\nYou need to have ffmpeg and ffprobe installed on the host running the script.\n\n\n## Example:\nThis is an example using the CRF Analyzer method.\n\n##### Code:\n```python\n# -*- coding: utf8 -*-\n\nfrom pertitleanalysis import per_title_analysis as pta\n\n# create your template encoding ladder\nPROFILE_LIST = []\nPROFILE_LIST.append(pta.EncodingProfile(1920, 1080, 4500000, 2000000, 6000000, True))\nPROFILE_LIST.append(pta.EncodingProfile(1280, 720, 3400000, 1300000, 4500000, True))\nPROFILE_LIST.append(pta.EncodingProfile(960, 540, 2100000, 700000, 300000, True))\nPROFILE_LIST.append(pta.EncodingProfile(640, 360, 1100000, 300000, 2000000, True))\nPROFILE_LIST.append(pta.EncodingProfile(480, 270, 750000, 300000, 900000, False))\nPROFILE_LIST.append(pta.EncodingProfile(480, 270, 300000, 150000, 500000, True))\nLADDER = pta.EncodingLadder(PROFILE_LIST)\n\n# Create a new CRF analysis provider \nANALYSIS = pta.CrfAnalyzer(\"{{ your_input_file_path }}\", LADDER)\n# Launch various analysis\nANALYSIS.process(1, 1920, 1080, 23, 2)\nANALYSIS.process(10, 1920, 1080, 23, 2)\n\n# Print results\nprint(ANALYSIS.get_json())\n```\n\n##### JSON ouput:\n```json\n{\n    \"analyses\": [\n        {\n            \"average_bitrate\": 3869192,\n            \"optimized_encoding_ladder\": {\n                \"encoding_profiles\": [\n                    {\n                        \"bitrate\": 3869192,\n                        \"bitrate_savings\": 630808,\n                        \"height\": 1080,\n                        \"width\": 1920\n                    },\n                    {\n                        \"bitrate\": 2923389,\n                        \"bitrate_savings\": 476611,\n                        \"height\": 720,\n                        \"width\": 1280\n                    },\n                    {\n                        \"bitrate\": 1805622,\n                        \"bitrate_savings\": 294378,\n                        \"height\": 540,\n                        \"width\": 960\n                    },\n                    {\n                        \"bitrate\": 945802,\n                        \"bitrate_savings\": 154198,\n                        \"height\": 360,\n                        \"width\": 640\n                    },\n                    {\n                        \"bitrate\": 644865,\n                        \"bitrate_savings\": 105135,\n                        \"height\": 270,\n                        \"width\": 480\n                    },\n                    {\n                        \"bitrate\": 257946,\n                        \"bitrate_savings\": 42054,\n                        \"height\": 270,\n                        \"width\": 480\n                    }\n                ],\n                \"overall_bitrate_ladder\": 10446816,\n                \"overall_bitrate_savings\": 1703184\n            },\n            \"optimal_bitrate\": 3869192,\n            \"parameters\": {\n                \"crf_value\": 23,\n                \"height\": 1080,\n                \"idr_interval\": 2,\n                \"method\": \"CRF\",\n                \"number_of_parts\": 1,\n                \"part_duration\": 60.0,\n                \"width\": 1920\n            },\n            \"processing_date\": \"2018-01-04 16:19:41.460371\",\n            \"standard_deviation\": null\n        },\n        {\n            \"average_bitrate\": 3844318.1,\n            \"optimized_encoding_ladder\": {\n                \"encoding_profiles\": [\n                    {\n                        \"bitrate\": 4747733,\n                        \"bitrate_savings\": -247733,\n                        \"height\": 1080,\n                        \"width\": 1920\n                    },\n                    {\n                        \"bitrate\": 3587176,\n                        \"bitrate_savings\": -187176,\n                        \"height\": 720,\n                        \"width\": 1280\n                    },\n                    {\n                        \"bitrate\": 2100000,\n                        \"bitrate_savings\": 0,\n                        \"height\": 540,\n                        \"width\": 960\n                    },\n                    {\n                        \"bitrate\": 1160556,\n                        \"bitrate_savings\": -60556,\n                        \"height\": 360,\n                        \"width\": 640\n                    },\n                    {\n                        \"bitrate\": 791288,\n                        \"bitrate_savings\": -41288,\n                        \"height\": 270,\n                        \"width\": 480\n                    },\n                    {\n                        \"bitrate\": 316515,\n                        \"bitrate_savings\": -16515,\n                        \"height\": 270,\n                        \"width\": 480\n                    }\n                ],\n                \"overall_bitrate_ladder\": 12703268,\n                \"overall_bitrate_savings\": -553268\n            },\n            \"optimal_bitrate\": 4747733.0,\n            \"parameters\": {\n                \"crf_value\": 23,\n                \"height\": 1080,\n                \"idr_interval\": 2,\n                \"method\": \"CRF\",\n                \"number_of_parts\": 10,\n                \"part_duration\": 6.0,\n                \"width\": 1920\n            },\n            \"processing_date\": \"2018-01-04 16:20:32.904371\",\n            \"standard_deviation\": 1372795.7042960383\n        }\n    ],\n    \"template_encoding_ladder\": {\n        \"encoding_profiles\": [\n            {\n                \"bitrate\": 4500000,\n                \"constraints\": {\n                    \"bitrate_factor\": 1.0,\n                    \"bitrate_max\": 6000000,\n                    \"bitrate_min\": 2000000,\n                    \"required\": true\n                },\n                \"height\": 1080,\n                \"width\": 1920\n            },\n            {\n                \"bitrate\": 3400000,\n                \"constraints\": {\n                    \"bitrate_factor\": 1.3235294117647058,\n                    \"bitrate_max\": 4500000,\n                    \"bitrate_min\": 1300000,\n                    \"required\": true\n                },\n                \"height\": 720,\n                \"width\": 1280\n            },\n            {\n                \"bitrate\": 2100000,\n                \"constraints\": {\n                    \"bitrate_factor\": 2.142857142857143,\n                    \"bitrate_max\": 2100000,\n                    \"bitrate_min\": 700000,\n                    \"required\": true\n                },\n                \"height\": 540,\n                \"width\": 960\n            },\n            {\n                \"bitrate\": 1100000,\n                \"constraints\": {\n                    \"bitrate_factor\": 4.090909090909091,\n                    \"bitrate_max\": 2000000,\n                    \"bitrate_min\": 300000,\n                    \"required\": true\n                },\n                \"height\": 360,\n                \"width\": 640\n            },\n            {\n                \"bitrate\": 750000,\n                \"constraints\": {\n                    \"bitrate_factor\": 6.0,\n                    \"bitrate_max\": 900000,\n                    \"bitrate_min\": 300000,\n                    \"required\": false\n                },\n                \"height\": 270,\n                \"width\": 480\n            },\n            {\n                \"bitrate\": 300000,\n                \"constraints\": {\n                    \"bitrate_factor\": 15.0,\n                    \"bitrate_max\": 500000,\n                    \"bitrate_min\": 150000,\n                    \"required\": true\n                },\n                \"height\": 270,\n                \"width\": 480\n            }\n        ],\n        \"overall_bitrate_ladder\": 12150000\n    },\n    \"input_file_path\": \"{{ your_input_file_path }}\"\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fencoding-ninja%2Fper-title-analysis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fencoding-ninja%2Fper-title-analysis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fencoding-ninja%2Fper-title-analysis/lists"}