int SrsFlvSegment::update_flv_metadata() { int ret = ERROR_SUCCESS; // no duration or filesize specified. if (!duration_offset || !filesize_offset) { return ret; } int64_t cur = fs->tellg(); // buffer to write the size. char* buf = new char[SrsAmf0Size::number()]; SrsAutoFreeA(char, buf); SrsBuffer stream; if ((ret = stream.initialize(buf, SrsAmf0Size::number())) != ERROR_SUCCESS) { return ret; } // filesize to buf. SrsAmf0Any* size = SrsAmf0Any::number((double)cur); SrsAutoFree(SrsAmf0Any, size); stream.skip(-1 * stream.pos()); if ((ret = size->write(&stream)) != ERROR_SUCCESS) { return ret; } // update the flesize. fs->lseek(filesize_offset); if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) { return ret; } // duration to buf SrsAmf0Any* dur = SrsAmf0Any::number((double)duration / 1000.0); SrsAutoFree(SrsAmf0Any, dur); stream.skip(-1 * stream.pos()); if ((ret = dur->write(&stream)) != ERROR_SUCCESS) { return ret; } // update the duration fs->lseek(duration_offset); if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) { return ret; } // reset the offset. fs->lseek(cur); return ret; }
int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) { int ret = ERROR_SUCCESS; SrsAmf0Any* any = (SrsAmf0Any*)amf0; SrsStream stream; if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { return ret; } if ((ret = any->write(&stream)) != ERROR_SUCCESS) { return ret; } return ret; }
VOID TEST(AMF0Test, ApiAnyAssert) { SrsStream s; SrsAmf0Any* o = NULL; char buf[1024]; memset(buf, 0, sizeof(buf)); EXPECT_EQ(ERROR_SUCCESS, s.initialize(buf, sizeof(buf))); // read any if (true) { s.reset(); s.current()[0] = 0x12; EXPECT_NE(ERROR_SUCCESS, srs_amf0_read_any(&s, &o)); EXPECT_TRUE(NULL == o); srs_freep(o); } // any convert if (true) { o = SrsAmf0Any::str(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_string()); } if (true) { o = SrsAmf0Any::number(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_number()); } if (true) { o = SrsAmf0Any::boolean(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_boolean()); } if (true) { o = SrsAmf0Any::null(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_null()); } if (true) { o = SrsAmf0Any::undefined(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_undefined()); } if (true) { o = SrsAmf0Any::object(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_object()); } if (true) { o = SrsAmf0Any::ecma_array(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_ecma_array()); } if (true) { o = SrsAmf0Any::strict_array(); SrsAutoFree(SrsAmf0Any, o); EXPECT_TRUE(o->is_strict_array()); } // empty object if (true) { o = SrsAmf0Any::object(); SrsAutoFree(SrsAmf0Any, o); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(1+3, s.pos()); } // empty ecma array if (true) { o = SrsAmf0Any::ecma_array(); SrsAutoFree(SrsAmf0Any, o); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(1+4+3, s.pos()); } // strict array if (true) { o = SrsAmf0Any::strict_array(); SrsAutoFree(SrsAmf0Any, o); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(1+4, s.pos()); } }
VOID TEST(AMF0Test, ApiAnyIO) { SrsStream s; SrsAmf0Any* o = NULL; char buf[1024]; memset(buf, 0, sizeof(buf)); EXPECT_EQ(ERROR_SUCCESS, s.initialize(buf, sizeof(buf))); // object eof if (true) { s.reset(); s.current()[2] = 0x09; o = SrsAmf0Any::object_eof(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_EQ(3, s.pos()); s.reset(); s.current()[0] = 0x01; EXPECT_NE(ERROR_SUCCESS, o->read(&s)); } if (true) { s.reset(); o = SrsAmf0Any::object_eof(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_EQ(3, s.pos()); s.skip(-3); EXPECT_EQ(0x09, s.read_3bytes()); } // string if (true) { s.reset(); o = SrsAmf0Any::str("winlin"); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(2, s.read_1bytes()); EXPECT_EQ(6, s.read_2bytes()); EXPECT_EQ('w', s.current()[0]); EXPECT_EQ('n', s.current()[5]); s.reset(); s.current()[3] = 'x'; EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_STREQ("xinlin", o->to_str().c_str()); } // number if (true) { s.reset(); o = SrsAmf0Any::number(10); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(0, s.read_1bytes()); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_DOUBLE_EQ(10, o->to_number()); } // boolean if (true) { s.reset(); o = SrsAmf0Any::boolean(true); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(1, s.read_1bytes()); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_TRUE(o->to_boolean()); } if (true) { s.reset(); o = SrsAmf0Any::boolean(false); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(1, s.read_1bytes()); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_FALSE(o->to_boolean()); } // null if (true) { s.reset(); o = SrsAmf0Any::null(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(5, s.read_1bytes()); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_TRUE(o->is_null()); } // undefined if (true) { s.reset(); o = SrsAmf0Any::undefined(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); EXPECT_EQ(6, s.read_1bytes()); s.reset(); EXPECT_EQ(ERROR_SUCCESS, o->read(&s)); EXPECT_EQ(o->total_size(), s.pos()); EXPECT_TRUE(o->is_undefined()); } // any: string if (true) { s.reset(); o = SrsAmf0Any::str("winlin"); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); SrsAutoFree(SrsAmf0Any, po); ASSERT_TRUE(po->is_string()); EXPECT_STREQ("winlin", po->to_str().c_str()); } // any: number if (true) { s.reset(); o = SrsAmf0Any::number(10); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); SrsAutoFree(SrsAmf0Any, po); ASSERT_TRUE(po->is_number()); EXPECT_DOUBLE_EQ(10, po->to_number()); } // any: boolean if (true) { s.reset(); o = SrsAmf0Any::boolean(true); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); SrsAutoFree(SrsAmf0Any, po); ASSERT_TRUE(po->is_boolean()); EXPECT_TRUE(po->to_boolean()); } // any: null if (true) { s.reset(); o = SrsAmf0Any::null(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); SrsAutoFree(SrsAmf0Any, po); ASSERT_TRUE(po->is_null()); } // any: undefined if (true) { s.reset(); o = SrsAmf0Any::undefined(); SrsAutoFree(SrsAmf0Any, o); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); EXPECT_EQ(o->total_size(), s.pos()); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); SrsAutoFree(SrsAmf0Any, po); ASSERT_TRUE(po->is_undefined()); } // mixed any if (true) { s.reset(); o = SrsAmf0Any::str("winlin"); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); srs_freep(o); o = SrsAmf0Any::number(10); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); srs_freep(o); o = SrsAmf0Any::boolean(true); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); srs_freep(o); o = SrsAmf0Any::null(); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); srs_freep(o); o = SrsAmf0Any::undefined(); EXPECT_EQ(ERROR_SUCCESS, o->write(&s)); srs_freep(o); s.reset(); SrsAmf0Any* po = NULL; EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); ASSERT_TRUE(po->is_string()); EXPECT_STREQ("winlin", po->to_str().c_str()); srs_freep(po); EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); ASSERT_TRUE(po->is_number()); EXPECT_DOUBLE_EQ(10, po->to_number()); srs_freep(po); EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); ASSERT_TRUE(po->is_boolean()); EXPECT_TRUE(po->to_boolean()); srs_freep(po); EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); ASSERT_TRUE(po->is_null()); srs_freep(po); EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po)); ASSERT_TRUE(NULL != po); ASSERT_TRUE(po->is_undefined()); srs_freep(po); } }
int SrsFlvSegment::write_metadata(SrsSharedPtrMessage* metadata) { int ret = ERROR_SUCCESS; if (duration_offset || filesize_offset) { return ret; } SrsBuffer stream; if ((ret = stream.initialize(metadata->payload, metadata->size)) != ERROR_SUCCESS) { return ret; } SrsAmf0Any* name = SrsAmf0Any::str(); SrsAutoFree(SrsAmf0Any, name); if ((ret = name->read(&stream)) != ERROR_SUCCESS) { return ret; } SrsAmf0Object* obj = SrsAmf0Any::object(); SrsAutoFree(SrsAmf0Object, obj); if ((ret = obj->read(&stream)) != ERROR_SUCCESS) { return ret; } // remove duration and filesize. obj->set("filesize", NULL); obj->set("duration", NULL); // add properties. obj->set("service", SrsAmf0Any::str(RTMP_SIG_SRS_SERVER)); obj->set("filesize", SrsAmf0Any::number(0)); obj->set("duration", SrsAmf0Any::number(0)); int size = name->total_size() + obj->total_size(); char* payload = new char[size]; SrsAutoFreeA(char, payload); // 11B flv header, 3B object EOF, 8B number value, 1B number flag. duration_offset = fs->tellg() + size + 11 - SrsAmf0Size::object_eof() - SrsAmf0Size::number(); // 2B string flag, 8B number value, 8B string 'duration', 1B number flag filesize_offset = duration_offset - SrsAmf0Size::utf8("duration") - SrsAmf0Size::number(); // convert metadata to bytes. if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) { return ret; } if ((ret = name->write(&stream)) != ERROR_SUCCESS) { return ret; } if ((ret = obj->write(&stream)) != ERROR_SUCCESS) { return ret; } // to flv file. if ((ret = enc->write_metadata(18, payload, size)) != ERROR_SUCCESS) { return ret; } return ret; }