একদিন আমার মিডিয়া পাইপলাইন আউটপুটের একটি অংশ প্রকাশ করা বন্ধ করে দিল। কারণ ছিল এমন একটি ত্রুটি, যা প্রথম দেখায় প্রায় হাস্যকর লাগছিল:
Invalid CFR packet duration: 5580 ticks, expected 5625
ডিকোডার ক্র্যাশ করেনি এবং FFmpeg H.264 ফাইলও তৈরি করেছিল। এনকোডিংয়ের পরে আমার ভ্যালিডেটর ফাইলটি বাতিল করছিল, কারণ আউটপুটটি স্থির ফ্রেম রেট হওয়ার কথা, অথচ একটি প্যাকেট আমার নির্ধারিত সময়-গ্রিডে ছিল না।
কাজটি আবার চালালাম। আবার 5580। আরেকবার চালালাম। আবারও 5580। পরে অন্য একটি উৎসও একই মানে ব্যর্থ হলো। এই পুনরাবৃত্তি গুরুত্বপূর্ণ প্রমাণ ছিল: এটি সাময়িক নেটওয়ার্ক সমস্যা বা বিরল race condition নয়; লঙ্ঘনটি নির্ধারিত এবং পুনরুৎপাদনযোগ্য ছিল।
পরে দ্বিতীয় একটি ব্যর্থতা পেলাম, দেখতে একই ধরনের হলেও প্রযুক্তিগতভাবে আলাদা। 24 fps এবং 90,000-টিক ভিডিও ট্র্যাকে প্রতিটি সাধারণ নমুনার সময়কাল ঠিক 3750 টিক হওয়ার কথা। ভ্যালিডেটর পেল 3751।
এই দুই সংখ্যাকে শুধু “FFmpeg রাউন্ডিং করে” বলে এক কারণের মধ্যে ফেলা ঠিক নয়। 5580 আর 5625-এর পার্থক্য 45 টিক, অর্থাৎ ঠিক 0.5 ms। 3751 আর 3750-এর পার্থক্য মাত্র এক টিক, প্রায় 11.1 মাইক্রোসেকেন্ড।
এই দুই ত্রুটি আমাকে চারটি ধারণা আলাদা করে দেখতে বাধ্য করেছে, যেগুলো আগে আমি “FPS” শব্দের নিচে গুলিয়ে ফেলতাম: ফ্রেম রেট, time base, PTS/DTS এবং প্যাকেটের সময়কাল।
CFR শুধু “16 fps” লেখা একটি লেবেল নয়
এখন কোনো তৈরি ফাইলকে CFR বললে আমি শুধু বোঝাই না যে ffprobe সুন্দর করে 16/1 বা 24/1 দেখাচ্ছে।
আমার পাইপলাইনে CFR একটি কঠোর নিয়ম: প্রদর্শনের সময় নিয়মিত গ্রিডে থাকবে এবং প্রতিটি সাধারণ ভিডিও নমুনার সময়কাল হবে সেই গ্রিডের এক ধাপ।
16 fps-এ একটি ফ্রেমের সময়কাল:
1 / 16 = 0.0625 s = 62.5 ms
90,000-টিক ভিডিও ট্র্যাকে একই ব্যবধান নির্ভুল পূর্ণসংখ্যায় প্রকাশ করা যায়:
90000 / 16 = 5625 ticks
তাই 5625 ভ্যালিডেটরের ইচ্ছামতো ধ্রুবক নয়। এটি আউটপুট নিয়মের দুটি সিদ্ধান্ত—16 fps এবং 90,000 ticks/s—থেকে সরাসরি আসে।
এই নির্ভুল সমতা তখনই যুক্তিসঙ্গত, যখন অনুমোদিত ফ্রেম রেটগুলো timescale-কে নিঃশেষে ভাগ করে। কোনো cadence যদি একটিমাত্র পূর্ণসংখ্যা সময়কাল দিয়ে প্রকাশ করা না যায়, ভ্যালিডেটরকে বৈধ পূর্ণসংখ্যার pattern যাচাই করতে হবে; অসম্ভব একটি মান দাবি করা যাবে না।
ফ্রেম রেট, time base এবং MP4 timescale এক জিনিস নয়
- ফ্রেম রেট প্রদর্শনের ছন্দ বোঝায়। CFR 16 মানে প্রতি 62.5 ms-এ একটি ফ্রেম দেখানো হয়।
- FFmpeg time base একটি পূর্ণসংখ্যা timestamp এককের সময়কাল, যেমন
1/90000সেকেন্ড। - MP4 ট্র্যাকের timescale একই ধারণাকে প্রতি সেকেন্ডে এককের সংখ্যা হিসেবে প্রকাশ করে। 90,000 হলে এক এককের সময়কাল
1/90000সেকেন্ড। - PTS বলে ছবি কখন দেখানো হবে।
- DTS বলে এনকোড করা প্যাকেট কখন ডিকোড করতে হবে।
- প্যাকেটের সময়কাল স্ট্রিমের time base-এ নমুনার সময়কাল প্রকাশ করে।
B-ফ্রেম থাকলে PTS এবং DTS বৈধভাবেই আলাদা হতে পারে। তাই timestamps “ঠিক” করতে সরাসরি PTS = DTS করা বিপজ্জনক; setts-এর সরকারি নথিও B-ফ্রেম থাকলে এটি সুপারিশ করে না।
তাই আমার ভ্যালিডেটর দুই মানকে সমান করে না; ডিকোড ক্রম ও প্রদর্শন ক্রমের সম্পর্ক বৈধ কি না তা পরীক্ষা করে।
কেন 90,000-টিক ট্র্যাক বেছে নিয়েছিলাম
90,000 কোনো সার্বজনীন জাদুকরী সংখ্যা নয়। আমার জন্য এটি কাজে দিয়েছে কারণ পাইপলাইনে অনুমোদিত প্রতিটি ফ্রেম রেট একটি নির্ভুল পূর্ণসংখ্যা সময়কাল দেয়:
| ফ্রেম রেট | 90,000 টিক/s-এ ফ্রেমের সময়কাল |
|---|---|
| 10 fps | 9000 টিক |
| 12 fps | 7500 টিক |
| 15 fps | 6000 টিক |
| 16 fps | 5625 টিক |
| 18 fps | 5000 টিক |
| 20 fps | 4500 টিক |
| 24 fps | 3750 টিক |
| 25 fps | 3600 টিক |
| 30 fps | 3000 টিক |
মিলিসেকেন্ড-স্তরের উৎস timing-এর সঙ্গেও এর সম্পর্ক সুবিধাজনক:
1 ms = 90 ticks
FFmpeg-এর MP4 multiplexer video_track_timescale দেয়, তাই এই ট্র্যাক-গ্রিড স্পষ্টভাবে নির্ধারণ করা যায়। গ্রিড নিজে timing ঠিক করে না; এটি নিয়মটিকে মাপা ও যাচাই করা সম্ভব করে।
5580 আমাকে কোথায় খুঁজতে হবে তা বলেছিল
প্রথম ব্যর্থতাটিকে আবার সময়ে রূপান্তর করলে বিষয়টি পরিষ্কার হয়:
5580 / 90000 = 0.062 s = 62 ms
এটি এলোমেলো মান ছিল না। আমার একটি বাস্তব অ্যানিমেটেড উৎস ছিল: 3.063 সেকেন্ডে 49টি প্রদর্শিত ফ্রেম, আর ফ্রেমের বিলম্ব 62 ও 63 ms-এর মধ্যে পালা করে বদলাচ্ছিল:
49 / 3.063 ≈ 15.997 frames/s
62 ms + 63 ms = 125 ms
2 frames at 16 fps = 2 × 62.5 ms = 125 ms
উৎস স্তরে 62/63 ms পর্যায়ক্রম মিলিসেকেন্ড গ্রিডে 16 fps-এর খুব স্বাভাবিক আনুমানিক রূপ।
কিন্তু CFR 16 বেছে নেওয়ার পর আউটপুটের সাধারণ ফ্রেমের সময়কাল হওয়া উচিত 62.5 ms বা 5625 টিক।
তাই 5580 শক্তিশালী ইঙ্গিত ছিল যে উৎসের 62 ms সময়কাল এমন একটি ধাপ পর্যন্ত রয়ে গেছে, যেখানে timing ইতিমধ্যেই CFR গ্রিডে কোয়ান্টাইজ হয়ে যাওয়ার কথা।
প্রমাণের সীমা আমি পরিষ্কার রাখি। সংরক্ষিত লগ প্রমাণ করে 90 kHz-এ 5580 ঠিক 62 ms, এবং বাস্তব উৎসে 62/63 ms বিলম্ব ছিল। লগ একা প্রমাণ করে না কোন নির্দিষ্ট ফাংশন প্রথম ওই সময়কালকে এগোতে দিয়েছিল। এটি প্রক্রিয়া নিয়ে শক্তিশালী অনুমান, পরে কাল্পনিক কোড-লাইন বানানোর অনুমতি নয়।
1000 Hz ইনপুট ঘড়ি ভুল ছিল না
স্থাপত্যের এই অংশটি আমি FFmpeg 7.1.5 এবং ffconcat দিয়ে আলাদাভাবে পুনরুৎপাদন করেছিলাম। এই ইনপুটে:
duration 0.010
option framerate 1000
প্যাকেট timestamps কাঙ্ক্ষিত মিলিসেকেন্ড অবস্থান ধরে রেখেছিল:
0 ms
10 ms
20 ms
30 ms
একই প্রাথমিক ধাপে input rate 30 দিলে timing প্রায় 0 এবং 33.3 ms-এ কোয়ান্টাইজ হয়ে যাচ্ছিল।
অর্থাৎ 1000 Hz ইনপুট ঘড়ি সঠিক কাজ করছিল: নির্ভরযোগ্য উৎস বিলম্বকে 1 ms নির্ভুলতায় সংরক্ষণ করছিল। এর মানে চূড়ান্ত আউটপুট 1000 fps নয়।
millisecond-accurate source delays
↓
authoritative source timeline
↓
choose target CFR
↓
explicitly quantize onto CFR grid
↓
preserve that grid through encoding and muxing
উচ্চ ইনপুট নির্ভুলতা ত্রুটি নয়। ত্রুটি হলো উৎস timing থেকে লক্ষ্য CFR-এ যাওয়ার সীমা অস্পষ্ট রাখা।
CFR হলো নিয়ন্ত্রিত সময়-কোয়ান্টাইজেশন
62/63 ms উৎস দুই ফ্রেমের জোড়া হিসেবে 16 fps-এর সঙ্গে স্বাভাবিকভাবে মিলে যায়: দুটো মিলিয়ে 125 ms। কিন্তু চূড়ান্ত ফাইল 62, 63, 62, 63 ms সময়কাল রেখে শুধু “16 fps” ঘোষণা করতে পারে না; সেগুলো এখনও পরিবর্তনশীল সময়কাল।
62 ms, 63 ms, 62 ms, 63 ms
↓
62.5 ms, 62.5 ms, 62.5 ms, 62.5 ms
FFmpeg-এর fps ফিল্টার এই রূপান্তরের যুক্তিসঙ্গত জায়গা। ইনপুট timestamps এবং নির্বাচিত rounding policy অনুযায়ী ফ্রেম বাদ দেওয়া বা পুনরাবৃত্তি করে লক্ষ্য ফ্রেম রেট তৈরি করে।
একবার এই ধাপ কাঙ্ক্ষিত গ্রিড বানালে, পরে আরেকটি ধাপকে স্বতন্ত্রভাবে ফ্রেম-রেট রূপান্তর আবার করতে দেওয়া উচিত নয়। পাইপলাইনে একটিই ইচ্ছাকৃত quantization boundary থাকা উচিত।
তিনটি পুনরায় চেষ্টা কেন কিছুই বদলায়নি
FAIL: duration 5580, expected 5625
retry 1/3
FAIL: duration 5580, expected 5625
retry 2/3
FAIL: duration 5580, expected 5625
এটি ভিডিওর বাইরেও নির্ভরযোগ্যতার শিক্ষা। পুনরায় চেষ্টা সেই ব্যর্থতার জন্য, যা পরের চেষ্টায় চলে যেতে পারে: নেটওয়ার্ক ত্রুটি, সাময়িক স্টোরেজ সমস্যা, রিসোর্স চাপ বা অনুপলব্ধ dependency।
একই ইনপুট এবং একই অ্যালগরিদম থেকে নির্ধারিত নিয়ম-লঙ্ঘন হলে পুনরায় চেষ্টা সেটি ঠিক করে না।
- সাময়িক ব্যর্থতা — পুনরায় চেষ্টা সাহায্য করতে পারে;
- খারাপ ইনপুট — অন্য পথে পাঠান বা প্রত্যাখ্যান করুন;
- নির্ধারিত invariant ব্যর্থতা — পুনরায় চেষ্টা বন্ধ করে পাইপলাইন বিশ্লেষণ করুন।
বারবার পাওয়া 5580 তৃতীয় শ্রেণির ছিল।
তারপর 3750-এর বদলে 3751 পেলাম
24 fps-এ প্রত্যাশিত মান নির্ভুল পূর্ণসংখ্যা:
90000 / 24 = 3750 ticks
তবুও একটি বাস্তব concat করা আউটপুটে একটি প্যাকেটের সময়কাল ছিল:
3751 ticks
পার্থক্য মাত্র:
1 / 90000 s ≈ 11.111 µs
কোনো দর্শক এক টিক বুঝবে না। তাই ভ্যালিডেটরে ±1 সহনশীলতা দেওয়া খুব লোভনীয় ছিল।
আমি দিইনি। এই গ্রিডে 24 fps-এর জন্য 3750 নির্ভুলভাবে উপস্থাপনযোগ্য। তাই 3751 অনিবার্য representation compromise নয়; কোথাও সঠিক গ্রিডের invariant হারানোর প্রমাণ।
স্ট্রিম কপি মানে timestamps অপরিবর্তিত থাকবে—এমন নয়
সামঞ্জস্যপূর্ণ H.264 খণ্ডগুলো দ্বিতীয় lossy encoding ছাড়া concat করা হচ্ছিল:
ffmpeg -f concat -safe 0 -i segments.ffconcat \
-c:v copy \
final.mp4
-c:v copy মানে সংকুচিত H.264 ডেটা ডিকোড করে পুনরায় এনকোড করা হয় না। এর মানে এই নয় যে multiplexing স্তরে timing নিয়ে কোনো কাজ হয় না।
concat demuxer-এর নথি স্পষ্টভাবে বলে যে প্রতিটি ফাইলের সময়কাল পরের ফাইলের timestamps সামঞ্জস্য করতে ব্যবহৃত হয়। FFmpeg বিভিন্ন rational time base-এর মধ্যে পূর্ণসংখ্যা timestamps rescale করে, আর libavutil স্পষ্ট rounding mode-সহ rescaling function দেয়।
এটি আমার নির্দিষ্ট 3751-এর একমাত্র কারণ হিসেবে concat-কে প্রমাণ করে না। কিন্তু “bitstream কপি হয়েছে, তাই packet timestamps বদলাতে পারে না” ধারণাটি ভুল।
সংকুচিত ছবির অভিন্নতা এবং timestamp-গ্রিডের অভিন্নতা আলাদা বৈশিষ্ট্য।
PTS এবং DTS এক সুন্দর সমীকরণ দিয়ে ঠিক করা যায় না
PTS = N * frame_duration
DTS = N * frame_duration
H.264-এ B-ফ্রেম থাকলে এটি ভুল হতে পারে, কারণ ডিকোড ক্রম এবং প্রদর্শন ক্রম আলাদা হতে পারে।
সঠিক লক্ষ্য হলো নির্ভরযোগ্য segment timeline ব্যবহার করে জানা প্রদর্শন-গ্রিড ও packet duration পুনরুদ্ধার করা, বৈধ decode-order সম্পর্ক বজায় রেখে।
এই কারণেই আমি প্রসঙ্গবিহীন “জাদুকরী setts expression” প্রকাশ করি না। সঠিক expression segment boundaries, নির্বাচিত rates এবং চূড়ান্ত timeline তৈরির timing metadata-র ওপর নির্ভর করে।
কেন setts ব্যবহার করেছি
FFmpeg-এর setts bitstream filter ভিডিও decode বা পুনরায় encode না করে packet PTS, DTS, duration এবং output time base বদলাতে পারে।
concat-এর পরে normalization-এর জন্য এটি সঠিক স্তর ছিল: H.264 ডেটা অপরিবর্তিত রাখা, কিন্তু জানা segment metadata থেকে তৈরি packet timeline আবার প্রয়োগ করা।
known segment timeline
+ known CFR
+ 90000-tick grid
↓
known valid packet positions and durations
↓
normalize packet timing
↓
validate again
এটি “duration 3751 হলে এক কমিয়ে দাও” নয়। সংশোধন timing model থেকে আসতে হবে, আজকের error message থেকে নয়।
আমি ±1 টিক সহনশীলতা কেন মানিনি
অনেক সিস্টেমে ছোট সহনশীলতা সঠিক। নির্বাচিত পূর্ণসংখ্যা time base-এ cadence নির্ভুলভাবে উপস্থাপন করা না গেলে ভ্যালিডেটরকে প্রয়োজনীয় rounding pattern মডেল করতে হবে।
আমার নিয়ম অন্যরকম ছিল: অনুমোদিত rates এমনভাবে সীমিত যে 90000 / fps একটি পূর্ণসংখ্যা হয়:
16 fps → 5625
24 fps → 3750
30 fps → 3000
প্রত্যাশিত duration নির্ভুলভাবে উপস্থাপনযোগ্য হলে সাধারণ ±1 অব্যাখ্যাত invariant violation-কে নীরবে গ্রহণযোগ্য করে দেয়।
এক টিক দৃশ্যত অপ্রাসঙ্গিক। কিন্তু নকশা করা নিয়মটি কেন হারালাম তা অপ্রাসঙ্গিক নয়।
- গ্রিড যদি স্বভাবত পর্যায়ক্রমিক পূর্ণসংখ্যা duration চায়, সেই pattern যাচাই করুন;
- duration নির্ভুল পূর্ণসংখ্যা হওয়ার কথা হলে সেই পূর্ণসংখ্যাটিই দাবি করুন;
- ভ্যালিডেটর পাস করানোর সার্বজনীন শর্টকাট হিসেবে ±1 ব্যবহার করবেন না।
প্যাকেট স্তরে CFR কীভাবে যাচাই করি
avg_frame_rate-এর মতো stream metadata উপকারী সারাংশ, কিন্তু এই নিয়মের জন্য যথেষ্ট নয়।
ffprobe -v error \
-select_streams v:0 \
-show_streams \
-show_packets \
-of json \
final.mp4
আমি বাস্তব stream time base এবং প্রতিটি প্যাকেটের pts, dts, duration দেখি।
expected = 90000 / 16 // 5625
for each normal video packet:
assert packet.duration == 5625
assert decode ordering is legal
assert PTS/DTS relationship is legal for the codec
assert presentation timeline matches planned frame count and duration
“সাধারণ প্যাকেট” কথাটি গুরুত্বপূর্ণ। edit list, trimming, ইচ্ছাকৃত বিশেষ terminal sample বা অন্য container behavior স্পষ্ট modeling চাইতে পারে। এটি সার্বজনীন MP4 নিয়ম নয়।
কিন্তু যে generator-এর গঠন আমার নিয়ন্ত্রণে, সেখানে কঠোর যাচাই “প্রায় 16 fps” বলার চেয়ে অনেক বেশি উপকারী।
মেটাডেটা যাচাই এবং পূর্ণ ডিকোডিং আলাদা প্রশ্নের উত্তর দেয়
নিখুঁত timestamps পুরো H.264 stream ডিকোড হবে তা প্রমাণ করে না। আবার পরিষ্কার decode timing contract ঠিক আছে তাও প্রমাণ করে না।
ffprobe / packet validation
→ structure, timestamps, durations, stream parameters
full decode
→ whether the complete compressed stream can actually be decoded
প্যাকেট পরীক্ষার পরও আমি এটি চালাই:
ffmpeg -v error -xerror -err_detect explode \
-i final.mp4 -f null -
দুই ধাপই পাস করার পর ফাইল প্রকাশযোগ্য হয়। encoder-এর exit code 0 এখন আর আমার কাছে “সম্পূর্ণ” হওয়ার সংজ্ঞা নয়।
দুই ব্যর্থতা আসলে কী প্রমাণ করেছে
5580-এর ক্ষেত্রে আমি নিশ্চিত করতে পারি: পুনরায় চেষ্টায় একই নির্ধারিত মান এসেছে; 90 kHz-এ 5580 ঠিক 62 ms; বাস্তব উৎসে 62/63 ms বিলম্ব ছিল; CFR 16-এর জন্য 62.5 ms বা 5625 টিক দরকার; এবং 1000 Hz ইনপুট পরীক্ষা মিলিসেকেন্ড বিলম্ব ঠিকভাবে সংরক্ষণ করেছে।
এগুলো উৎসের duration এমন একটি ধাপ পর্যন্ত ফাঁস হওয়াকে শক্তিশালী ব্যাখ্যা বানায়, যেখানে CFR আগেই তৈরি হয়ে যাওয়ার কথা। কিন্তু সংরক্ষিত error line নির্দিষ্ট সমস্যাযুক্ত function প্রমাণ করে না।
3751-এর ক্ষেত্রে নিশ্চিত: বাস্তব আউটপুটে 24 fps-এর প্রত্যাশিত 3750-এর বদলে 3751-টিক প্যাকেট ছিল; পাইপলাইন stream-copy concat করত; concat-এর পরে packet normalization-এ setts সমাধানের অংশ হয়েছিল; এবং FFmpeg concat timestamp adjustment ও packet-level timestamp rewriting নথিভুক্ত করে।
তথ্যগুলো integer rescaling বা multiplexing/concat boundary rounding-এর সঙ্গে সামঞ্জস্যপূর্ণ, কিন্তু “concat সবসময় এক টিক যোগ করে” এমন সার্বজনীন দাবি সমর্থন করে না।
এখনকার কার্যপ্রবাহ
- অনুমান করা FPS field নয়, নির্ভরযোগ্য উৎস timeline পুনর্গঠন করি।
- মূল মিলিসেকেন্ড বিলম্ব যথেষ্ট নির্ভুল input clock-এ সংরক্ষণ করি।
- লক্ষ্য CFR আলাদাভাবে বেছে নিই।
- উৎস timeline স্পষ্টভাবে CFR গ্রিডে কোয়ান্টাইজ করি।
- সম্ভব হলে এমন track timescale বেছে নিই যা অনুমোদিত rates নির্ভুলভাবে উপস্থাপন করে।
- এনকোডিংয়ের পরে অন্য ধাপকে স্বতন্ত্রভাবে frame-rate conversion আবার করতে দিই না।
- concat-এর আগে time base, frame count, PTS/DTS এবং packet duration যাচাই করি।
- stream-copy concat-এর আগে codec configuration ও timing compatibility যাচাই করি।
- concat-এর পরে packet grid আবার পরীক্ষা করি;
-c:v copy-কে timestamp identity-র প্রমাণ মনে করি না। - normalization দরকার হলে জানা timeline থেকে নির্ণয় করে packet level-এ প্রয়োগ করি।
- সব প্যাকেট আবার যাচাই করি।
- চূড়ান্ত ফাইল সম্পূর্ণ decode করি।
- নিয়ম পাস করলেই atomically প্রকাশ করি।
শেষ পর্যন্ত যে নিয়মটি রয়ে গেছে: CFR একটি পূর্ণসংখ্যা timing contract
আগে 16 fps প্রায় স্বতঃস্পষ্ট মনে হতো। এখন নয়।
time base = 1/90000
normal frame duration = 5625 ticks
presentation cadence = 62.5 ms
packet timeline follows that grid
PTS/DTS remain legal for H.264 reordering
5580 গুরুত্বপূর্ণ ছিল কারণ এটি পুরোনো মিলিসেকেন্ড গ্রিড প্রকাশ করে দিয়েছিল। 3751 গুরুত্বপূর্ণ ছিল ঠিক এজন্যই যে এটি প্রায় অদৃশ্য: মাত্র এক টিক প্রমাণ করেছিল সিস্টেম আর সেই invariant ধরে রাখছে না, যেটি নকশা অনুযায়ী ঠিক থাকার কথা।
আমার এখনকার নিয়ম: “CFR” লেবেল যাচাই করবেন না; যে timing থেকে লেবেলটি সত্য হওয়ার কথা, সেটাই যাচাই করুন।
প্রধান নথিপত্র
- FFmpeg: fps ফিল্টার — লক্ষ্য ফ্রেম রেট এবং PTS rounding policy।
- FFmpeg: MOV/MP4 ফরম্যাট —
video_track_timescaleএবং MP4 multiplexer বিকল্প। - FFmpeg: concat demuxer — ফাইল durations এবং concat করা inputs-এর মধ্যে timestamp adjustment।
- FFmpeg: setts bitstream filter — packet PTS, DTS, duration ও time base rewriting।
- ffprobe নথি — streams ও packets পরীক্ষা।
- FFmpeg libavutil: সময়ের হিসাব ও timestamp rescaling — rational timestamp rescaling এবং স্পষ্ট rounding modes।