| @@ -3,6 +3,7 @@ · 2 unmodified lines |
| 3 | #include <thread.h> | 3 | #include <thread.h> |
| 4 | #include <bio.h> | 4 | #include <bio.h> |
| 5 | #include <libsec.h> | 5 | #include <libsec.h> |
| | 6 | #include "ivf.h" |
| 6 | | 7 | |
| 7 | enum { | 8 | enum { |
| 8 | Port = 1935, | 9 | Port = 1935, |
| @@ -23,21 +24,8 @@ enum { · 14 unmodified lines |
| 23 | FlHdr = 1<<1, | 24 | FlHdr = 1<<1, |
| 24 | | 25 | |
| 25 | Sigsz = 1536, | 26 | Sigsz = 1536, |
| 26 | }; | | |
| 27 | | | |
| 28 | typedef struct Frame Frame; | | |
| 29 | typedef struct IVF IVF; | | |
| 30 | | | |
| 31 | struct Frame { | | |
| 32 | u64int ts; | | |
| 33 | u8int *buf; | | |
| 34 | int bufsz; | | |
| 35 | int sz; | | |
| 36 | }; | | |
| 37 | | 27 | |
| 38 | struct IVF { | 28 | ChanCtl = 3, |
| 39 | u16int w, h; | | |
| 40 | u32int tbdenum, tbnum; | | |
| 41 | }; | 29 | }; |
| 42 | | 30 | |
| 43 | int mainstacksize = 65536; | 31 | int mainstacksize = 65536; |
| @@ -252,121 +240,6 @@ flvdata(u8int *p, u8int *e, u32int pts, u32int dts, void *data, int sz, int type · 208 unmodified lines |
| 252 | return amfi32(p, e, p-p0); | 240 | return amfi32(p, e, p-p0); |
| 253 | } | 241 | } |
| 254 | | 242 | |
| 255 | static int | | |
| 256 | Bu16le(Biobuf *b, u16int *o) | | |
| 257 | { | | |
| 258 | int x; | | |
| 259 | | | |
| 260 | x = Bgetc(b); | | |
| 261 | x |= Bgetc(b)<<8; | | |
| 262 | *o = x; | | |
| 263 | if(x < 0) | | |
| 264 | werrstr("failed to read 2 bytes"); | | |
| 265 | | | |
| 266 | return x < 0 ? -1 : 0; | | |
| 267 | } | | |
| 268 | | | |
| 269 | static int | | |
| 270 | Bu32le(Biobuf *b, u32int *o) | | |
| 271 | { | | |
| 272 | int x, i; | | |
| 273 | | | |
| 274 | *o = 0; | | |
| 275 | for(i = 0; i < 4; *o |= x<<(i*8), i++){ | | |
| 276 | if((x = Bgetc(b)) < 0){ | | |
| 277 | werrstr("failed to read 4 bytes"); | | |
| 278 | return -1; | | |
| 279 | } | | |
| 280 | } | | |
| 281 | | | |
| 282 | return 0; | | |
| 283 | } | | |
| 284 | | | |
| 285 | static int | | |
| 286 | Bu64le(Biobuf *b, u64int *o) | | |
| 287 | { | | |
| 288 | int x, i; | | |
| 289 | | | |
| 290 | *o = 0; | | |
| 291 | for(i = 0; i < 8; *o |= x<<(i*8), i++){ | | |
| 292 | if((x = Bgetc(b)) < 0){ | | |
| 293 | werrstr("failed to read 8 bytes"); | | |
| 294 | return -1; | | |
| 295 | } | | |
| 296 | } | | |
| 297 | | | |
| 298 | return 0; | | |
| 299 | } | | |
| 300 | | | |
| 301 | static int | | |
| 302 | ivfopen(Biobuf *v, IVF *o) | | |
| 303 | { | | |
| 304 | u16int hlen; | | |
| 305 | u8int b[6]; | | |
| 306 | | | |
| 307 | if(Bread(v, b, 6) != 6 || Bu16le(v, &hlen) < 0 || | | |
| 308 | hlen < 0x20 || memcmp(b, "DKIF", 4) != 0 || | | |
| 309 | Bread(v, b, 4) != 4){ | | |
| 310 | werrstr("invalid header"); | | |
| 311 | goto err; | | |
| 312 | } | | |
| 313 | if(memcmp(b, "AVC1", 4) != 0){ | | |
| 314 | werrstr("not H.264"); | | |
| 315 | goto err; | | |
| 316 | } | | |
| 317 | if(Bu16le(v, &o->w) < 0 || | | |
| 318 | Bu16le(v, &o->h) < 0 || | | |
| 319 | Bu32le(v, &o->tbdenum) < 0 || | | |
| 320 | Bu32le(v, &o->tbnum) < 0){ | | |
| 321 | werrstr("invalid data"); | | |
| 322 | goto err; | | |
| 323 | } | | |
| 324 | if(Bseek(v, hlen, 0) != hlen){ | | |
| 325 | werrstr("broken stream"); | | |
| 326 | goto err; | | |
| 327 | } | | |
| 328 | | | |
| 329 | return 0; | | |
| 330 | err: | | |
| 331 | werrstr("ivf: %r"); | | |
| 332 | return -1; | | |
| 333 | } | | |
| 334 | | | |
| 335 | static int | | |
| 336 | ivfread(Biobuf *v, Frame *f) | | |
| 337 | { | | |
| 338 | u8int *buf; | | |
| 339 | u64int ts; | | |
| 340 | u32int sz; | | |
| 341 | int n; | | |
| 342 | | | |
| 343 | if(Bu32le(v, &sz) < 0 || Bu64le(v, &ts) < 0 || (int)sz < 0){ | | |
| 344 | /* eof */ | | |
| 345 | f->sz = 0; | | |
| 346 | return 0; | | |
| 347 | } | | |
| 348 | buf = f->buf; | | |
| 349 | if(sz > f->bufsz){ | | |
| 350 | if((buf = realloc(f->buf, sz)) == nil){ | | |
| 351 | werrstr("frame is too big: %d bytes", sz); | | |
| 352 | goto err; | | |
| 353 | } | | |
| 354 | f->buf = buf; | | |
| 355 | } | | |
| 356 | if((n = Bread(v, buf, sz)) != sz){ | | |
| 357 | werrstr("short read (%d < %d)", n, sz); | | |
| 358 | goto err; | | |
| 359 | } | | |
| 360 | f->buf = buf; | | |
| 361 | f->sz = sz; | | |
| 362 | f->ts = ts; | | |
| 363 | | | |
| 364 | return 0; | | |
| 365 | err: | | |
| 366 | werrstr("ivf: %r"); | | |
| 367 | return -1; | | |
| 368 | } | | |
| 369 | | | |
| 370 | static int | 243 | static int |
| 371 | handshake(int f, char *path) | 244 | handshake(int f, char *path) |
| 372 | { | 245 | { |
| @@ -450,7 +323,8 @@ threadmain(int argc, char **argv) · 77 unmodified lines |
| 450 | Biobuf *a, *v, o; | 323 | Biobuf *a, *v, o; |
| 451 | u8int *b, *p, *e; | 324 | u8int *b, *p, *e; |
| 452 | int bufsz, fd; | 325 | int bufsz, fd; |
| 453 | Frame f; | 326 | u64int ns; |
| | 327 | IVFrame f; |
| 454 | IVF ivf; | 328 | IVF ivf; |
| 455 | | 329 | |
| 456 | a = nil; | 330 | a = nil; |
| @@ -474,6 +348,8 @@ threadmain(int argc, char **argv) · 17 unmodified lines |
| 474 | sysfatal("no video specified"); | 348 | sysfatal("no video specified"); |
| 475 | if(ivfopen(v, &ivf) != 0) | 349 | if(ivfopen(v, &ivf) != 0) |
| 476 | sysfatal("%r"); | 350 | sysfatal("%r"); |
| | 351 | if(strcmp(ivf.type, "AVC1") != 0) |
| | 352 | sysfatal("not H.264"); |
| 477 | srand(time(nil)); | 353 | srand(time(nil)); |
| 478 | if((fd = rtmpdial(argv[0])) < 0 || Binit(&o, fd, OWRITE) < 0) | 354 | if((fd = rtmpdial(argv[0])) < 0 || Binit(&o, fd, OWRITE) < 0) |
| 479 | sysfatal("%r"); | 355 | sysfatal("%r"); |
| @@ -499,7 +375,8 @@ threadmain(int argc, char **argv) · 19 unmodified lines |
| 499 | sysfatal("memory"); | 375 | sysfatal("memory"); |
| 500 | e = b + bufsz; | 376 | e = b + bufsz; |
| 501 | } | 377 | } |
| 502 | if((p = flvdata(b, e, f.ts, f.ts, f.buf, f.sz, Fvideo, FlHdr)) == nil) | 378 | ns = ivfns(&ivf, f.ts); |
| | 379 | if((p = flvdata(b, e, ns, ns, f.buf, f.sz, Fvideo, FlHdr)) == nil) |
| 503 | sysfatal("video: flvdata: %r"); | 380 | sysfatal("video: flvdata: %r"); |
| 504 | if(Bwrite(&o, b, p-b) < 0) | 381 | if(Bwrite(&o, b, p-b) < 0) |
| 505 | sysfatal("%r"); | 382 | sysfatal("%r"); |