📄 media-app.cc
字号:
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- *///// Copyright (c) 1997 by the University of Southern California// All rights reserved.//// Permission to use, copy, modify, and distribute this software and its// documentation in source and binary forms for non-commercial purposes// and without fee is hereby granted, provided that the above copyright// notice appear in all copies and that both the copyright notice and// this permission notice appear in supporting documentation. and that// any documentation, advertising materials, and other materials related// to such distribution and use acknowledge that the software was// developed by the University of Southern California, Information// Sciences Institute. The name of the University may not be used to// endorse or promote products derived from this software without// specific prior written permission.//// THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about// the suitability of this software for any purpose. THIS SOFTWARE IS// PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.//// Other copyrights might apply to parts of this software and are so// noted when applicable.//// Implementation of media application//// $Header: /nfs/jade/vint/CVSROOT/ns-2/rap/media-app.cc,v 1.12 1999/11/18 23:14:31 haoboy Exp $#include <stdarg.h>#include "template.h"#include "media-app.h"#include "utilities.h"//----------------------------------------------------------------------// Classes related to a multimedia object//// MediaSegment// MediaSegmentList: segments in a layer// MediaPage: a stored multimedia object (stream)//----------------------------------------------------------------------MediaSegment::MediaSegment(const HttpMediaData& d) : flags_(0){ start_ = d.st(); end_ = d.et(); if (d.is_last()) set_last(); if (d.is_pref()) set_pref();}void MediaSegmentList::add(const MediaSegment& s) { MediaSegment* tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->before(s))) { tmp = tmp->next(); } // Append at the tail, or the first element in list if (tmp == NULL) { length_ += s.datasize(); if ((tail_ != NULL) && ((MediaSegment *)tail_)->overlap(s)) // Don't need to merge because it's merged at the end ((MediaSegment*)tail_)->merge(s); else { MediaSegment *p = new MediaSegment(s); if (head_ == NULL) head_ = tail_ = p; else append(p, tail_); } if (getsize() != length_) { fprintf(stderr, "MediaSegmentList corrupted: Point 1.\n"); abort(); } return; } // Update total stored length ONLY IF s is not in tmp. if (tmp->in(s)) { fprintf(stderr, "MediaSegmentList: get a seg (%d %d) which is already in cache!\n", s.start(), s.end()); fprintf(stderr, "List contents: "); print();#if 1 //Tcl::instance().eval("[Test instance] flush-trace"); //abort();#endif // XXX Don't abort, simply continue return; } // Insert a MediaSegment into list. Note: Don't do merge! if (tmp->overlap(s)) { length_ += (s.datasize() - tmp->merge(s)); } else { MediaSegment *p = new MediaSegment(s); insert(p, tmp); tmp = p; length_ += s.datasize(); } if (getsize() != length_) { fprintf(stderr, "MediaSegmentList corrupted: Point 2.\n"); abort(); } merge_seg(tmp); if (getsize() != length_) { fprintf(stderr, "MediaSegmentList corrupted: Point 3.\n"); abort(); }}void MediaSegmentList::merge_seg(MediaSegment* tmp){ // See if <tmp> can be merged with next segments MediaSegment *q = tmp->next(); while (q && q->overlap(*tmp)) {#if 1 if ((tmp->start() == q->start()) && (tmp->end() == q->end())) { abort(); }#endif tmp->merge(*q); detach(q); delete q; q = tmp->next(); } // See if <tmp> can be merged with previous segments q = tmp->prev(); while (q && q->overlap(*tmp)) { tmp->merge(*q); assert(tail_ != q); detach(q); delete q; q = tmp->prev(); }}int MediaSegmentList::in(const MediaSegment& s){ MediaSegment* tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->before(s))) tmp = tmp->next(); // If all segments are before s, or the first segment which isn't // before s doesn't overlap with s, s isn't in this list. if ((tmp == NULL) || !s.in(*tmp)) return 0; else return 1;}// Get the next segment which is not before 's', but with the same size// as the given 's'. This segment may not overlap with s. MediaSegment MediaSegmentList::get_nextseg(const MediaSegment& s) { MediaSegment res(0, 0); // If unsuccessful, return start() = 0 MediaSegment* tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->before(s))) tmp = tmp->next(); if (tmp == NULL) { res.set_last(); return res; } assert(tmp->end() > s.start());// // Don't return a segment which do not *OVERLAP* with s // // (boundary overlap is excluded).// if ((tmp->end() <= s.start()) || (tmp->start() >= s.end())) // return res; // XXX How to flag that no more data is available in the future?? res = s; int orig_size = s.datasize(); if (res.start() < tmp->start()) { // |-------| (s) ---> time axis // |--------| (tmp) // // The start time of s is invalid, we need to adjust both // the start time (and size if necessary) res.set_start(tmp->start()); if (tmp->datasize() < orig_size) // Not enough data available?? res.set_datasize(tmp->datasize()); else res.set_datasize(orig_size); } else if (res.end() > tmp->end()) { // |---------| (s) ---> time axis // |-------| (tmp) // // The start time in s is valid, but we may need to adjust the // end time (i.e., size) of s. res.set_datasize(tmp->end()-res.start()); } // Falling through means that the requested segment is available // and can be returned as it is. assert(res.datasize() <= tmp->datasize()); if ((res.end() == tmp->end()) && (tmp->next() == NULL)) // This is the last data segment of the layer res.set_last(); return res;}// Note that evicting all segments in this layer may not leave enough // space, so we return the number of bytes evicted from this layerint MediaSegmentList::evict_tail(int size){ int sz = size, tz; MediaSegment *tmp = (MediaSegment *)tail_; while ((tmp != NULL) && (sz > 0)) { // Reduce the last segment's size and adjust its playout time tz = tmp->evict_tail(sz); length_ -= tz; sz -= tz; if (tmp->datasize() == 0) { // This segment is empty now detach(tmp); delete tmp; tmp = (MediaSegment *)tail_; } } return size - sz;}// Evicting <size> from the head of the listint MediaSegmentList::evict_head(int size){ int sz = size, tz; MediaSegment *tmp = (MediaSegment *)head_; while ((tmp != NULL) && (sz > 0)) { // Reduce the last segment's size and adjust its playout time tz = tmp->evict_head(sz); sz -= tz; length_ -= tz; if (tmp->datasize() == 0) { // This segment is empty now detach(tmp); delete tmp; tmp = (MediaSegment *)head_; } } return size - sz;}// Evict all segments before <offset> from head and returns the size of // evicted segments.int MediaSegmentList::evict_head_offset(int offset){ int sz = 0; MediaSegment *tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->start() < offset)) { if (tmp->end() <= offset) { // delete whole segment sz += tmp->datasize(); length_ -= tmp->datasize(); detach(tmp); delete tmp; tmp = (MediaSegment *)head_; } else { // remove part of the segment sz += offset - tmp->start(); length_ -= offset - tmp->start(); tmp->set_start(offset); } } if (head_ == NULL) tail_ = NULL; return sz;}// Return a list of "holes" between the given offsetsMediaSegmentList MediaSegmentList::check_holes(const MediaSegment& s){ MediaSegmentList res; // empty list MediaSegment* tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->before(s))) tmp = tmp->next(); // If all segments are before s, s is a hole if (tmp == NULL) { res.add(s); return res; } // If s is within *tmp, there is no hole if (s.in(*tmp)) return res; // Otherwise return a list of holes int soff, eoff; soff = s.start(); eoff = s.end(); while ((tmp != NULL) && (tmp->overlap(s))) { if (soff < tmp->start()) { // Only refetches the missing part res.add(MediaSegment(soff, min(eoff, tmp->start())));#if 1 // DEBUG ONLY // Check if these holes are really holes! if (in(MediaSegment(soff, min(eoff, tmp->start())))) { fprintf(stderr, "Wrong hole: (%d %d) ", soff, min(eoff, tmp->start())); fprintf(stderr, "tmp(%d %d), s(%d %d)\n", tmp->start(), tmp->end(), soff, eoff); fprintf(stderr, "List content: "); print(); }#endif } soff = tmp->end(); tmp = tmp->next(); } if (soff < eoff) { res.add(MediaSegment(soff, eoff));#if 1 // DEBUG ONLY // Check if these holes are really holes! if (in(MediaSegment(soff, eoff))) { fprintf(stderr, "Wrong hole #2: (%d %d)\n", soff, eoff); fprintf(stderr, "List content: "); print(); }#endif }#if 0 check_integrity();#endif return res;}void MediaSegmentList::check_integrity(){ MediaSegment *p, *q; p = (MediaSegment*)head_; while (p != NULL) { q = p; p = p->next(); if (p == NULL) break; if (!q->before(*p)) { fprintf(stderr, "Invalid segment added: (%d %d), (%d %d)\n", q->start(), q->end(), p->start(), p->end()); abort(); } }}// Return the portion in s that is overlap with any segments in this list// Sort of complementary to check_holes(), but it does not return a list, // hence smaller overhead. int MediaSegmentList::overlap_size(const MediaSegment& s) const{ int res = 0; MediaSegment* tmp = (MediaSegment *)head_; while ((tmp != NULL) && (tmp->before(s))) tmp = tmp->next(); // If all segments are before s, there's no overlap if (tmp == NULL) return 0; // If s is within *tmp, entire s overlaps with the list if (s.in(*tmp)) return s.datasize(); // Otherwise adds all overlapping parts together. int soff, eoff; soff = s.start(); eoff = s.end(); while ((tmp != NULL) && (tmp->overlap(s))) { res += min(eoff, tmp->end()) - max(soff, tmp->start()); soff = tmp->end(); tmp = tmp->next(); } return res;}// Debug onlyvoid MediaSegmentList::print() { MediaSegment *p = (MediaSegment *)head_; int i = 0, sz = 0; while (p != NULL) { printf("(%d, %d) ", p->start(), p->end()); sz += p->datasize(); p = p->next(); if (++i % 8 == 0) printf("\n"); } printf("\nTotal = %d\n", sz);}// Debug onlyint MediaSegmentList::getsize(){ MediaSegment *p = (MediaSegment *)head_; int sz = 0; while (p != NULL) { sz += p->datasize(); p = p->next(); } return sz;}// Print into a char array with a given size. Abort if the size is exceeded.char* MediaSegmentList::dump2buf(){ char *buf = new char[1024]; char *b = buf; MediaSegment *p = (MediaSegment *)head_; int i = 0, sz = 1024; buf[0] = 0; while (p != NULL) { // XXX snprintf() should either be in libc or implemented // by TclCL (see Tcl2.cc there). i = snprintf(b, sz, "{%d %d} ", p->start(), p->end()); sz -= i; // Boundary check: if less than 50 bytes, allocate new buf if (sz < 50) { char *tmp = new char[strlen(buf)+1024]; strcpy(tmp, buf); delete []buf; buf = tmp; b = buf + strlen(buf); sz += 1024; } else b += i; p = p->next(); } return buf;}HttpMediaData::HttpMediaData(const char* sender, const char* page, int layer, int st, int et) : HttpData(MEDIA_DATA, 0), layer_(layer), st_(st), et_(et), flags_(0){ assert(strlen(page)+1 <= (size_t)HTTP_MAXURLLEN); strcpy(page_, page); assert(strlen(sender)+1 <= (size_t)HTTP_MAXURLLEN); strcpy(sender_, sender);}static class MappClass : public TclClass {public: MappClass() : TclClass("Application/MediaApp") {} TclObject* create(int argc, const char*const* argv) { if (argc > 4) return (new MediaApp(argv[4])); return NULL; }} class_mapp;MediaApp::MediaApp(const char* page) : log_(0), num_layer_(0), last_layer_(0){ strcpy(page_, page); // Initialize all layer data pointers for (int i = 0; i < MAX_LAYER; i++) data_[i].set_start(0); bind("segmentSize_", &seg_size_);}void MediaApp::start(){ fprintf(stderr, "MediaApp::start() not supported\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -