+// General pts/dts strategy:
+//
+// Getting pts and dts right with variable frame rate (VFR) and B-frames can be a
+// bit tricky. This strategy roughly matches what x264 seems to do: We take in
+// the pts as the frames are encoded, and reuse that as dts in the same order,
+// slightly offset.
+//
+// If we don't have B-frames (only I and P), this means pts == dts always.
+// This is the simple case. Now consider the case with a single B-frame:
+//
+// I B P B P
+// pts: 30 40 50 60 70
+//
+// Since we always inherently encode P-frames before B-frames, this means that
+// we see them in this order, which we can _almost_ use for dts:
+//
+// dts: 30 50 40 70 60
+//
+// the only problem here is that for the B-frames, pts < dts. We solve this by
+// priming the queue at the very start with some made-up dts:
+//
+// I B P B P
+// pts: 30 40 50 60 70
+// dts: xx 30 50 40 70 60
+//
+// Now we have all the desirable properties: pts >= dts, successive dts delta
+// is never larger than the decoder can figure out (assuming, of course,
+// the pts has that property), and there's minimal lag between pts and dts.
+// For the made-up dts, we assume 1/60 sec per frame, which should generally
+// be reasonable. dts can go negative, but this is corrected using global_delay()
+// by delaying both pts and dts (although we probably don't need to).
+//
+// If there's more than one B-frame possible, we simply insert more of them
+// (here shown with some irregular spacing, assuming B-frames don't depend
+// on each other and simply go back-to-front):
+//
+// I B B B P B B B P
+// pts: 30 40 55 60 65 66 67 68 80
+// dts: xx yy zz 30 65 60 55 40 80 68 67 66
+class DTSReorderer {
+public:
+ DTSReorderer(int num_b_frames) : num_b_frames(num_b_frames) {}
+
+ void push_pts(int64_t pts)
+ {
+ if (buf.empty() && num_b_frames > 0) { // First frame.
+ int64_t base_dts = pts - num_b_frames * (TIMEBASE / TYPICAL_FPS);
+ for (int i = 0; i < num_b_frames; ++i) {
+ buf.push(base_dts + i * (TIMEBASE / TYPICAL_FPS));
+ }
+ }
+ buf.push(pts);
+ }
+
+ int64_t pop_dts()
+ {
+ assert(!buf.empty());
+ int64_t dts = buf.front();
+ buf.pop();
+ return dts;
+ }
+
+private:
+ const int num_b_frames;
+ queue<int64_t> buf;
+};