mirror of
https://github.com/acgnhiki/blrec.git
synced 2024-12-27 00:50:14 +08:00
parent
adf6e36b8f
commit
b4123e7982
11
.github/workflows/portable.yml
vendored
11
.github/workflows/portable.yml
vendored
@ -40,11 +40,6 @@ jobs:
|
||||
- name: Unzip Python archive
|
||||
run: Expand-Archive -LiteralPath "python.zip" -DestinationPath "build\python"
|
||||
|
||||
- name: Enter build directory
|
||||
run: |
|
||||
Set-Location -Path "build"
|
||||
ls
|
||||
|
||||
- name: Rename ffmpeg directory
|
||||
working-directory: build
|
||||
run: Rename-Item -Path $($env:FFMPEG_ARCHIVE_NAME).Substring(0, $($env:FFMPEG_ARCHIVE_NAME).Length - 4) "ffmpeg"
|
||||
@ -83,12 +78,6 @@ jobs:
|
||||
working-directory: build
|
||||
run: Copy-Item "${{ github.workspace }}\run.bat" -Destination ".\run.bat"
|
||||
|
||||
- name: Exit build directory
|
||||
working-directory: build
|
||||
run: |
|
||||
ls
|
||||
Set-Location -Path ".."
|
||||
|
||||
- name: Zip files
|
||||
run: |
|
||||
ls build
|
||||
|
@ -1,5 +1,10 @@
|
||||
# 更新日志
|
||||
|
||||
## 1.6.1
|
||||
|
||||
- 修复 bug (issue #37, 38, 40)
|
||||
- 接收到错误的数据自动换线路 (issue #43)
|
||||
|
||||
## 1.6.0
|
||||
|
||||
- 更新 Pushplus 消息推送 url (issue #26)
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
__prog__ = 'blrec'
|
||||
__version__ = '1.6.0'
|
||||
__version__ = '1.6.1'
|
||||
__github__ = 'https://github.com/acgnhiki/blrec'
|
||||
|
@ -84,6 +84,7 @@ class FLVStreamRecorder(
|
||||
analyse_data=True,
|
||||
dedup_join=True,
|
||||
save_extra_metadata=True,
|
||||
backup_timestamp=True,
|
||||
)
|
||||
|
||||
def update_size(size: int) -> None:
|
||||
@ -182,6 +183,7 @@ class FLVStreamRecorder(
|
||||
url = self._get_live_stream_url()
|
||||
except FlvStreamCorruptedError as e:
|
||||
logger.warning(repr(e))
|
||||
self._use_candidate_stream = not self._use_candidate_stream
|
||||
url = self._get_live_stream_url()
|
||||
|
||||
def _streaming(self, url: str) -> None:
|
||||
|
@ -387,6 +387,7 @@ class HLSStreamRecorder(
|
||||
analyse_data=True,
|
||||
dedup_join=True,
|
||||
save_extra_metadata=True,
|
||||
backup_timestamp=True,
|
||||
)
|
||||
self._stream_processor.size_updates.subscribe(update_size)
|
||||
|
||||
|
1
src/blrec/data/webapp/66.8d16a032cbce41ed.js
Normal file
1
src/blrec/data/webapp/66.8d16a032cbce41ed.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/694.dbcbd5e1953ea55d.js
Normal file
1
src/blrec/data/webapp/694.dbcbd5e1953ea55d.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -10,6 +10,6 @@
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<noscript>Please enable JavaScript to continue using this application.</noscript>
|
||||
<script src="runtime.23c91f03d62c595a.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.8a8c73fae6ff9291.js" type="module"></script>
|
||||
<script src="runtime.459a2fcc68ef4fa7.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.8a8c73fae6ff9291.js" type="module"></script>
|
||||
|
||||
</body></html>
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"configVersion": 1,
|
||||
"timestamp": 1649386979751,
|
||||
"timestamp": 1650082907617,
|
||||
"index": "/index.html",
|
||||
"assetGroups": [
|
||||
{
|
||||
@ -14,15 +14,15 @@
|
||||
"/103.5b5d2a6e5a8a7479.js",
|
||||
"/146.92e3b29c4c754544.js",
|
||||
"/45.c90c3cea2bf1a66e.js",
|
||||
"/66.d8b06f1fef317761.js",
|
||||
"/694.92a3e0c2fc842a42.js",
|
||||
"/869.95d68b28a4188d76.js",
|
||||
"/66.8d16a032cbce41ed.js",
|
||||
"/694.dbcbd5e1953ea55d.js",
|
||||
"/869.ac675e78fa0ea7cf.js",
|
||||
"/common.858f777e9296e6f2.js",
|
||||
"/index.html",
|
||||
"/main.8a8c73fae6ff9291.js",
|
||||
"/manifest.webmanifest",
|
||||
"/polyfills.4b08448aee19bb22.js",
|
||||
"/runtime.23c91f03d62c595a.js",
|
||||
"/runtime.459a2fcc68ef4fa7.js",
|
||||
"/styles.1f581691b230dc4d.css"
|
||||
],
|
||||
"patterns": []
|
||||
@ -1637,9 +1637,9 @@
|
||||
"/103.5b5d2a6e5a8a7479.js": "cc0240f217015b6d4ddcc14f31fcc42e1c1c282a",
|
||||
"/146.92e3b29c4c754544.js": "3824de681dd1f982ea69a065cdf54d7a1e781f4d",
|
||||
"/45.c90c3cea2bf1a66e.js": "e5bfb8cf3803593e6b8ea14c90b3d3cb6a066764",
|
||||
"/66.d8b06f1fef317761.js": "43676d9dc886b5624dadecc50f17d4972b183d2d",
|
||||
"/694.92a3e0c2fc842a42.js": "f8f093029b9996b3db0c4e738bf9f8573fba8392",
|
||||
"/869.95d68b28a4188d76.js": "cd1add38c89b1df3c0783b74c931b51839f1c530",
|
||||
"/66.8d16a032cbce41ed.js": "a473089370c2fe27f96a778acf1e709dc5770b31",
|
||||
"/694.dbcbd5e1953ea55d.js": "41973de76799b085188903f46cc6974f20395741",
|
||||
"/869.ac675e78fa0ea7cf.js": "f45052016cb5201d5784b3f261e719d96bd1b153",
|
||||
"/assets/animal/panda.js": "fec2868bb3053dd2da45f96bbcb86d5116ed72b1",
|
||||
"/assets/animal/panda.svg": "bebd302cdc601e0ead3a6d2710acf8753f3d83b1",
|
||||
"/assets/fill/.gitkeep": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
@ -3234,11 +3234,11 @@
|
||||
"/assets/twotone/warning.js": "fb2d7ea232f3a99bf8f080dbc94c65699232ac01",
|
||||
"/assets/twotone/warning.svg": "8c7a2d3e765a2e7dd58ac674870c6655cecb0068",
|
||||
"/common.858f777e9296e6f2.js": "b68ca68e1e214a2537d96935c23410126cc564dd",
|
||||
"/index.html": "114f00ffcd1f7fa5aaaa7f2fcf3109f26c77c715",
|
||||
"/index.html": "be9d178866ccd58dfdc2a4c1b375ab030302163b",
|
||||
"/main.8a8c73fae6ff9291.js": "41a5a5a8fb5cda4cfa0e28532812594816257122",
|
||||
"/manifest.webmanifest": "62c1cb8c5ad2af551a956b97013ab55ce77dd586",
|
||||
"/polyfills.4b08448aee19bb22.js": "8e73f2d42cc13ca353cea5c886d930bd6da08d0d",
|
||||
"/runtime.23c91f03d62c595a.js": "0819f1120ed1e37c2ad069ef949147450c951069",
|
||||
"/runtime.459a2fcc68ef4fa7.js": "a68b948e588e75f8cb2fb5315ac41623e7c6ed1e",
|
||||
"/styles.1f581691b230dc4d.css": "6f5befbbad57c2b2e80aae855139744b8010d150"
|
||||
},
|
||||
"navigationUrls": [
|
||||
|
@ -1 +1 @@
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var i=m[e];if(void 0!==i)return i.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(i,t,f,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=f();void 0!==d&&(i=d)}}return i}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,f,o]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",66:"d8b06f1fef317761",103:"5b5d2a6e5a8a7479",146:"92e3b29c4c754544",592:"858f777e9296e6f2",694:"92a3e0c2fc842a42",869:"95d68b28a4188d76"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="blrec:";r.l=(t,f,o,n)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+o),a.src=r.tu(t)),e[t]=[f];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=f){var a=new Promise((u,s)=>n=e[f]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(f),l=new Error;r.l(c,u=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(f&&f(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var i=m[e];if(void 0!==i)return i.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(i,t,o,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,o,f]=e[n],c=!0,l=0;l<t.length;l++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,f<a&&(a=f));if(c){e.splice(n--,1);var d=o();void 0!==d&&(i=d)}}return i}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,o,f]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",66:"8d16a032cbce41ed",103:"5b5d2a6e5a8a7479",146:"92e3b29c4c754544",592:"858f777e9296e6f2",694:"dbcbd5e1953ea55d",869:"ac675e78fa0ea7cf"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="blrec:";r.l=(t,o,f,n)=>{if(e[t])e[t].push(o);else{var a,c;if(void 0!==f)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+f){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+f),a.src=r.tu(t)),e[t]=[o];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(o,f)=>{var n=r.o(e,o)?e[o]:void 0;if(0!==n)if(n)f.push(n[2]);else if(666!=o){var a=new Promise((u,s)=>n=e[o]=[u,s]);f.push(n[2]=a);var c=r.p+r.u(o),l=new Error;r.l(c,u=>{if(r.o(e,o)&&(0!==(n=e[o])&&(e[o]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+o+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+o,o)}else e[o]=0},r.O.j=o=>0===e[o];var i=(o,f)=>{var l,d,[n,a,c]=f,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(o&&o(f);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
@ -37,8 +37,15 @@ __all__ = 'FlvParser', 'FlvDumper'
|
||||
|
||||
|
||||
class FlvParser:
|
||||
def __init__(self, stream: RandomIO) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
stream: RandomIO,
|
||||
backup_timestamp: bool = False,
|
||||
restore_timestamp: bool = False,
|
||||
) -> None:
|
||||
self._stream = stream
|
||||
self._backup_timestamp = backup_timestamp
|
||||
self._restore_timestamp = restore_timestamp
|
||||
self._reader = StructReader(stream)
|
||||
|
||||
def parse_header(self) -> FlvHeader:
|
||||
@ -108,19 +115,42 @@ class FlvParser:
|
||||
|
||||
def parse_flv_tag_header(self, data: bytes) -> FlvTagHeader:
|
||||
reader = StructReader(BytesIO(data))
|
||||
|
||||
flag = reader.read_ui8()
|
||||
filtered = bool(flag & 0b0010_0000)
|
||||
if filtered:
|
||||
raise FlvDataError('Unsupported Filtered FLV Tag', data)
|
||||
|
||||
tag_type = TagType(flag & 0b0001_1111)
|
||||
data_size = reader.read_ui24()
|
||||
timestamp = reader.read_ui24()
|
||||
timestamp_extended = reader.read_ui8()
|
||||
timestamp = timestamp_extended << 24 | timestamp
|
||||
stream_id = reader.read_ui24()
|
||||
return FlvTagHeader(
|
||||
filtered, tag_type, data_size, timestamp, stream_id
|
||||
)
|
||||
|
||||
if self._backup_timestamp:
|
||||
return FlvTagHeader(
|
||||
filtered=filtered,
|
||||
tag_type=tag_type,
|
||||
data_size=data_size,
|
||||
timestamp=timestamp_extended << 24 | timestamp,
|
||||
stream_id=timestamp,
|
||||
)
|
||||
elif self._restore_timestamp:
|
||||
return FlvTagHeader(
|
||||
filtered=filtered,
|
||||
tag_type=tag_type,
|
||||
data_size=data_size,
|
||||
timestamp=stream_id,
|
||||
stream_id=stream_id,
|
||||
)
|
||||
else:
|
||||
return FlvTagHeader(
|
||||
filtered=filtered,
|
||||
tag_type=tag_type,
|
||||
data_size=data_size,
|
||||
timestamp=timestamp_extended << 24 | timestamp,
|
||||
stream_id=stream_id,
|
||||
)
|
||||
|
||||
def parse_audio_tag_header(self, data: bytes) -> AudioTagHeader:
|
||||
reader = StructReader(BytesIO(data))
|
||||
|
@ -16,9 +16,21 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FlvReader:
|
||||
def __init__(self, stream: RandomIO) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
stream: RandomIO,
|
||||
*,
|
||||
backup_timestamp: bool = False,
|
||||
restore_timestamp: bool = False,
|
||||
) -> None:
|
||||
self._stream = stream
|
||||
self._parser = FlvParser(stream)
|
||||
self._backup_timestamp = backup_timestamp
|
||||
self._restore_timestamp = restore_timestamp
|
||||
self._parser = FlvParser(
|
||||
stream,
|
||||
backup_timestamp=backup_timestamp,
|
||||
restore_timestamp=restore_timestamp,
|
||||
)
|
||||
|
||||
def read_header(self) -> FlvHeader:
|
||||
header = self._parser.parse_header()
|
||||
|
@ -31,7 +31,8 @@ from .exceptions import (
|
||||
CutStream,
|
||||
)
|
||||
from .common import (
|
||||
is_audio_tag, is_video_tag, is_metadata_tag, parse_metadata,
|
||||
is_metadata_tag, parse_metadata, is_audio_tag, is_video_tag,
|
||||
is_video_sequence_header, is_audio_sequence_header,
|
||||
is_audio_data_tag, is_video_data_tag, enrich_metadata, update_metadata,
|
||||
is_data_tag, read_tags_in_duration,
|
||||
)
|
||||
@ -63,6 +64,8 @@ class StreamProcessor:
|
||||
analyse_data: bool = False,
|
||||
dedup_join: bool = False,
|
||||
save_extra_metadata: bool = False,
|
||||
backup_timestamp: bool = False,
|
||||
restore_timestamp: bool = False,
|
||||
) -> None:
|
||||
self._file_manager = file_manager
|
||||
self._parameters_checker = ParametersChecker()
|
||||
@ -79,6 +82,8 @@ class StreamProcessor:
|
||||
self._analyse_data = analyse_data
|
||||
self._dedup_join = dedup_join
|
||||
self._save_x_metadata = save_extra_metadata
|
||||
self._backup_timestamp = backup_timestamp
|
||||
self._restore_timestamp = restore_timestamp
|
||||
|
||||
self._cancelled: bool = False
|
||||
self._finalized: bool = False
|
||||
@ -223,7 +228,12 @@ class StreamProcessor:
|
||||
def _process_stream(self, stream: RandomIO) -> None:
|
||||
logger.debug(f'Processing the {self._stream_count}th stream...')
|
||||
|
||||
self._in_reader = FlvReaderWithTimestampFix(stream)
|
||||
self._in_reader = FlvReaderWithTimestampFix(
|
||||
stream,
|
||||
backup_timestamp=self._backup_timestamp,
|
||||
restore_timestamp=self._restore_timestamp,
|
||||
)
|
||||
|
||||
flv_header = self._read_header()
|
||||
self._has_audio = flv_header.has_audio()
|
||||
|
||||
@ -552,18 +562,23 @@ class StreamProcessor:
|
||||
return header
|
||||
|
||||
def _ensure_ts_correct(self, tag: FlvTag) -> None:
|
||||
if not is_audio_data_tag(tag) or not is_video_data_tag(tag):
|
||||
if not is_audio_data_tag(tag) and not is_video_data_tag(tag):
|
||||
return
|
||||
if tag.timestamp + self._delta < 0:
|
||||
self._delta = -tag.timestamp
|
||||
logger.warning('Incorrect timestamp: {}, new delta: {}'.format(
|
||||
tag, self._delta
|
||||
))
|
||||
self._delta = (
|
||||
self._last_tags[0].timestamp +
|
||||
self._in_reader.calc_interval(tag) - tag.timestamp
|
||||
)
|
||||
logger.warning(
|
||||
f'Incorrect timestamp, updated delta: {self._delta}\n'
|
||||
f'last output tag: {self._last_tags[0]}\n'
|
||||
f'current tag: {tag}'
|
||||
)
|
||||
|
||||
def _correct_ts(self, tag: FlvTag, delta: int) -> FlvTag:
|
||||
if delta == 0 and tag.timestamp >= 0:
|
||||
return tag
|
||||
return tag.evolve(timestamp=max(0, tag.timestamp + delta))
|
||||
return tag.evolve(timestamp=tag.timestamp + delta)
|
||||
|
||||
def _calc_delta_duplicated(self, last_duplicated_tag: FlvTag) -> int:
|
||||
return self._last_tags[0].timestamp - last_duplicated_tag.timestamp
|
||||
@ -764,8 +779,17 @@ class RobustFlvReader(FlvReader):
|
||||
|
||||
|
||||
class FlvReaderWithTimestampFix(RobustFlvReader):
|
||||
def __init__(self, stream: RandomIO) -> None:
|
||||
super().__init__(stream)
|
||||
def __init__(
|
||||
self,
|
||||
stream: RandomIO,
|
||||
backup_timestamp: bool = False,
|
||||
restore_timestamp: bool = False,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
stream,
|
||||
backup_timestamp=backup_timestamp,
|
||||
restore_timestamp=restore_timestamp,
|
||||
)
|
||||
self._last_tag: Optional[FlvTag] = None
|
||||
self._last_video_tag: Optional[VideoTag] = None
|
||||
self._last_audio_tag: Optional[AudioTag] = None
|
||||
@ -842,11 +866,17 @@ class FlvReaderWithTimestampFix(RobustFlvReader):
|
||||
if is_video_tag(tag):
|
||||
if self._last_video_tag is None:
|
||||
return False
|
||||
return tag.timestamp <= self._last_video_tag.timestamp
|
||||
if is_video_sequence_header(self._last_video_tag):
|
||||
return tag.timestamp < self._last_video_tag.timestamp
|
||||
else:
|
||||
return tag.timestamp <= self._last_video_tag.timestamp
|
||||
elif is_audio_tag(tag):
|
||||
if self._last_audio_tag is None:
|
||||
return False
|
||||
return tag.timestamp <= self._last_audio_tag.timestamp
|
||||
if is_audio_sequence_header(self._last_audio_tag):
|
||||
return tag.timestamp < self._last_audio_tag.timestamp
|
||||
else:
|
||||
return tag.timestamp <= self._last_audio_tag.timestamp
|
||||
else:
|
||||
return False
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
<nz-modal
|
||||
nzTitle="修改文件路径模板"
|
||||
nzCentered
|
||||
[nzFooter]="modalFooter"
|
||||
[(nzVisible)]="visible"
|
||||
[nzOkDisabled]="control.invalid || control.value.trim() === value"
|
||||
(nzOnOk)="handleConfirm()"
|
||||
(nzOnCancel)="handleCancel()"
|
||||
>
|
||||
<ng-container *nzModalContent>
|
||||
<form nz-form [formGroup]="settingsForm">
|
||||
|
@ -28,7 +28,7 @@ export function toBitRateString(
|
||||
let unit: string;
|
||||
|
||||
if (bitrate <= 0) {
|
||||
return '0 kbps/s';
|
||||
return '0' + spacer + 'kbps';
|
||||
}
|
||||
|
||||
if (bitrate < 1e6) {
|
||||
@ -60,7 +60,7 @@ export function toByteRateString(
|
||||
let unit: string;
|
||||
|
||||
if (rate <= 0) {
|
||||
return '0B/s';
|
||||
return '0' + spacer + 'B/s';
|
||||
}
|
||||
|
||||
if (rate < 1e3) {
|
||||
|
@ -86,7 +86,7 @@
|
||||
<span class="label">下载速度</span>
|
||||
<app-wave-graph [value]="data.task_status.dl_rate"></app-wave-graph>
|
||||
<span class="value">
|
||||
{{ data.task_status.dl_rate | datarate: { bitrate: true } }}
|
||||
{{ data.task_status.dl_rate * 8 | datarate: { bitrate: true } }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="info-item">
|
||||
|
Loading…
Reference in New Issue
Block a user