Last week we worked out why a phone camera's live stream stops after a few hours on mobile data: on a plan that says "1.5 GB/day (thereafter @ 64 Kbps)", the stream does not get cut off. It gets slowed to a speed far below YouTube's lowest listed bitrate. At that minimum (0.4 Mbps video plus 128 Kbps audio), 1.5 GB is about 6.3 hours.

That article ended with "a 1.5 GB/day plan covers a night, not a day and a night." This one tests a sharper question: which night? A daily plan has two quotas in play on any given night, the one that is running out and the one that renews at the reset. When you start the stream decides how much of each you get.

The answer turned out to be bigger than I expected, so here is the script, every number it printed, and the one assumption that can break it.

The model

Three inputs come from the operator and YouTube. All three are the same sourced figures as last week's article:

  • Daily quota: 1.5 GB, then 64 Kbps (Jio's ₹319 plan help page).
  • Reset time: Jio's help page says a daily quota "is renewed at midnight (between 00:00 hrs and 02:00 hrs)". Note the two-hour window. It matters below.
  • Stream rate: YouTube's minimum for 360p/480p H.264 is 0.4 Mbps, and its recommended stereo audio is 128 Kbps. Together: 528 Kbps.

The conversion is the same one as before:

MB per hour = kbps × 3600 ÷ 8 ÷ 1000 528 kbps → 237.6 MB per hour 

The script

#!/usr/bin/env python3 """Which hours can a daily-quota mobile plan carry a phone camera's live stream?""" import argparse def mb_per_hour(kbps): return kbps * 3600 / 8 / 1000 # kilobits per second -> MB per hour (1 MB = 1000 KB) def hhmm(h): m = round(h * 60) % (24 * 60) return f"{m // 60:02d}:{m % 60:02d}" def plan(quota_gb, kbps, start, other_mb, reset): rate = mb_per_hour(kbps) quota = quota_gb * 1000 old_left = max(quota - other_mb, 0) to_reset = (reset - start) % 24 rows = [] old_hours = min(old_left / rate, to_reset) rows.append((start, start + old_hours, "old day's quota")) if to_reset - old_hours > 0.01: # quota ran out before the reset rows.append((start + old_hours, start + to_reset, "64 Kbps gap")) new_start = start + to_reset rows.append((new_start, new_start + quota / rate, "new day's quota")) return rate, rows if __name__ == "__main__": p = argparse.ArgumentParser() p.add_argument("--quota-gb", type=float, default=1.5) p.add_argument("--kbps", type=float, default=528) # 400 video + 128 audio p.add_argument("--start", type=float, default=20) # 20 = 8 pm p.add_argument("--other-mb", type=float, default=0) # data used earlier today p.add_argument("--reset", type=float, default=0) # 0 = midnight p.add_argument("--best-start", action="store_true") a = p.parse_args() if a.best_start: # start so the old day's quota runs out exactly at the reset old_left = a.quota_gb * 1000 - a.other_mb a.start = (a.reset - old_left / mb_per_hour(a.kbps)) % 24 rate, rows = plan(a.quota_gb, a.kbps, a.start, a.other_mb, a.reset) print(f"{rate:.1f} MB per hour") for s, e, label in rows: print(f" {hhmm(s)} -> {hhmm(e)} {label} ({e - s:.1f} h)") 

It assumes the stream keeps going across the reset. The new quota is only useful if the stream is still connected, or reconnects on its own, when the speed comes back. Test that on your own setup before you rely on it (last week's article has a one-night test).

Run 1: the usual 8 pm start

$ python3 stream_window.py 237.6 MB per hour 20:00 -> 00:00 old day's quota (4.0 h) 00:00 -> 06:19 new day's quota (6.3 h) 

10.3 hours, but 4 hours on the old quota uses only about 950 MB of it. About 550 MB of the old day is never used. That is more than two hours of stream left on the table.

Run 2: start so the old quota ends exactly at the reset

$ python3 stream_window.py --best-start 237.6 MB per hour 17:41 -> 00:00 old day's quota (6.3 h) 00:00 -> 06:19 new day's quota (6.3 h) 

12.6 hours in one unbroken stretch, 17:41 to 06:19, from a plan that carries 6.3 hours a day. Nothing new is bought. The stretch simply uses the end of one day's quota and the start of the next.

The cost is real, so say it plainly: the new day's quota is gone by 06:19. If the SIM only serves the camera, that costs nothing, because the camera then records locally all day (recording to the phone uses no mobile data). If the SIM is also someone's phone, this plan leaves them on 64 Kbps all day.

Run 3: something else used data earlier today

$ python3 stream_window.py --other-mb 900 237.6 MB per hour 20:00 -> 22:32 old day's quota (2.5 h) 22:32 -> 00:00 64 Kbps gap (1.5 h) 00:00 -> 06:19 new day's quota (6.3 h) 

900 MB of app updates or backups earlier in the day, and the 8 pm stream dies at 22:32, with a 1.5-hour dead stretch before midnight. That is the "it stops at night and comes back by itself" pattern people report. --best-start --other-mb 300 moves the start to 18:57 to fill the window exactly. The fix that matters more is stopping the other data use (last week's article lists the settings).

Run 4: the two-hour reset window breaks the best start

Here is the assumption that catches people. Jio's page gives the reset as a window, 00:00 to 02:00, not a time. What if you planned for midnight and the reset came at 02:00?

$ python3 stream_window.py --start 17.6833 --reset 2 237.6 MB per hour 17:41 -> 00:00 old day's quota (6.3 h) 00:00 -> 02:00 64 Kbps gap (2.0 h) 02:00 -> 08:19 new day's quota (6.3 h) 

A two-hour hole from midnight to 2 am, the hours many people most want covered.

Now plan for the latest reset instead, and suppose it actually comes at midnight:

$ python3 stream_window.py --best-start --reset 2 237.6 MB per hour 19:41 -> 02:00 old day's quota (6.3 h) 02:00 -> 08:19 new day's quota (6.3 h) $ python3 stream_window.py --start 19.6833 --reset 0 237.6 MB per hour 19:41 -> 00:00 old day's quota (4.3 h) 00:00 -> 06:19 new day's quota (6.3 h) 

If the reset comes late, you get the full 12.6 hours, 19:41 to 08:19. If it comes early, there is no gap, just about 474 MB of the old quota left unused (1,500 − 4.32 × 237.6) and the stream ends at 06:19.

So the rule is asymmetric:

You plan for Reset actually at Result
00:00 (start 17:41) 00:00 12.6 h, no gap
00:00 (start 17:41) 02:00 2 h gap at 00:00–02:00
02:00 (start 19:41) 02:00 12.6 h, no gap
02:00 (start 19:41) 00:00 10.6 h, no gap, ~474 MB unused

Plan for the latest possible reset. The worst case costs you some unused data, never a hole in the night.

Run 5: why 720p does not fit any start time

$ python3 stream_window.py --kbps 3128 1407.6 MB per hour 20:00 -> 21:04 old day's quota (1.1 h) 21:04 -> 00:00 64 Kbps gap (2.9 h) 00:00 -> 01:04 new day's quota (1.1 h) 

YouTube's 720p minimum is 3 Mbps. At that rate, straddling the reset still gives about 2.1 hours in total. No start time rescues 720p on a 1.5 GB plan. Stream at 480p, and keep the full-quality footage in the local recording.

What the planner does not know

  • Your real MB per hour. The model uses YouTube's minimum and adds nothing for protocol overhead or other apps. Measure one hour of your own stream in the operator's app, then pass that rate through --kbps (MB per hour × 8 ÷ 3.6).
  • Your operator's reset rule. The 00:00–02:00 window is Jio's wording, read on 5 November 2026. Check your own plan.
  • Whether your stream survives the reset. That is a property of your app and your setup, not of the arithmetic. Test it.

Where Background Camera RemoteStream fits

Background Camera RemoteStream is the Android app this series is written around. It records with the screen off and keeps the video on the phone, so the hours the stream cannot cover are still recorded. Live view on the same Wi-Fi or hotspot (a Pro feature, per the Play listing) stays on the local network and does not use the SIM's quota. YouTube Live, also Pro per the listing, is the only part this planner is about. Check the listing for the current free vs Pro split.

Sources

Every output block above was printed by the script as shown, with Python 3. The hours are calculated, not measured on a phone.