| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| // -*- c++ -*- |
| // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
| |
| // O S C L _ M E D I A _ D A T A |
| |
| // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
| |
| /*! \addtogroup osclutil OSCL Util |
| * |
| * @{ |
| */ |
| |
| |
| /** \file oscl_media_data.h |
| \brief Defines a container class for media data made up of a collection of memory fragments. |
| */ |
| |
| #ifndef OSCL_MEDIA_DATA_H |
| #define OSCL_MEDIA_DATA_H |
| |
| #ifndef OSCL_BASE_H_INCLUDED |
| #include "oscl_base.h" |
| #endif |
| |
| #ifndef OSCL_MEM_BASIC_FUNCTIONS_H_INCLUDED |
| #include "oscl_mem_basic_functions.h" |
| #endif |
| |
| #ifndef OSCL_MEDIA_STATUS_H_INCLUDED |
| #include "oscl_media_status.h" |
| #endif |
| |
| typedef void (*BufferFreeFuncPtr)(void *); |
| |
| typedef uint32 MediaTimestamp; |
| |
| template <class T> class MemAllocator |
| { |
| public: |
| typedef T* pointer; |
| // virtual pointer allocate(size_t size, void *hint = 0) = 0; |
| virtual pointer allocate(void * hint = 0, const int num_reserved_frags = 1) = 0; |
| virtual void deallocate(pointer p) = 0; |
| virtual ~MemAllocator() {} |
| }; |
| |
| class BufferState; |
| /* Buffer referee (how about the "whistle blower" ?*/ |
| class BufferMgr |
| { |
| public: |
| virtual void BufferReleased(void* ptr, BufferState* state = NULL) = 0; |
| virtual ~BufferMgr() {} |
| }; |
| |
| |
| class BufferState |
| { |
| public: |
| BufferState(BufferFreeFuncPtr the_free_function, void *bufptr = 0) : |
| refcount(0), ptr(bufptr), free_function(the_free_function), buf_mgr(0) {}; |
| |
| BufferState(BufferMgr* the_buf_mgr = 0, void *bufptr = 0) : |
| refcount(0), ptr(bufptr), free_function(0), buf_mgr(the_buf_mgr) {}; |
| |
| void increment_refcnt() |
| { |
| ++refcount; |
| }; |
| void decrement_refcnt() |
| { |
| if (!(--refcount)) |
| { |
| if (buf_mgr) buf_mgr->BufferReleased(ptr, this); |
| else if (free_function) |
| { |
| free_function(ptr); |
| ptr = 0; |
| } |
| } |
| }; |
| |
| void bind(void *in_ptr, BufferFreeFuncPtr in_free_function) |
| { |
| refcount = 0; |
| ptr = in_ptr, free_function = in_free_function; |
| |
| }; |
| void bind(void *in_ptr, BufferMgr* in_buf_mgr) |
| { |
| refcount = 0; |
| ptr = in_ptr, buf_mgr = in_buf_mgr; |
| }; |
| |
| void *get_ptr() |
| { |
| return ptr; |
| }; |
| int32 get_refcount() |
| { |
| return refcount; |
| }; |
| |
| BufferFreeFuncPtr get_free_function() |
| { |
| return free_function; |
| }; |
| BufferMgr* get_buf_mgr() |
| { |
| return buf_mgr; |
| }; |
| |
| void reset() |
| { |
| refcount = 0; |
| ptr = 0; |
| }; |
| |
| private: |
| int32 refcount; |
| void *ptr; |
| BufferFreeFuncPtr free_function; // called to free the buffer |
| BufferMgr* buf_mgr; // called to free the buffer |
| }; |
| |
| |
| // BufferFragment is a special case of a memory |
| // fragment since it refers to fragments of a reference |
| // counted memory. The name is used to make this explicit. |
| class BufferFragment : public OsclMemoryFragment {}; |
| |
| |
| template <class ChainClass, uint32 max_frags> class BufFragGroup |
| { |
| public: |
| |
| |
| BufFragGroup(): next(0), num_fragments(0), length(0) |
| { |
| oscl_memset(fragments, 0, sizeof(fragments)); |
| oscl_memset(buffer_states, 0, sizeof(buffer_states)); |
| }; |
| |
| virtual ~BufFragGroup() {} |
| |
| int32 GetMaxFrags() const |
| { |
| return max_frags; |
| }; |
| int32 GetNumFrags() const |
| { |
| return num_fragments; |
| }; |
| uint32 GetLength() const |
| { |
| return length; |
| }; |
| |
| BufferFragment * GetFragment(const int32 idx); |
| |
| BufferState * GetBufferState(const int32 idx); |
| |
| void AppendNext(ChainClass* next_ptr) |
| { |
| next = next_ptr; |
| }; |
| ChainClass* GetNext() const |
| { |
| return next; |
| }; |
| |
| // make fragment array accessible to allow usage within socket |
| // send functions. |
| |
| protected: |
| |
| |
| // BufferFragment * GetFragment(const uint32 idx) const; |
| |
| |
| |
| virtual void Clear() |
| { |
| for (uint ii = 0 ; ii < num_fragments; ++ii) |
| { |
| if (buffer_states[ii]) |
| { |
| buffer_states[ii]->decrement_refcnt(); |
| } |
| } |
| num_fragments = length = 0; |
| oscl_memset(buffer_states, 0, sizeof(buffer_states)); |
| oscl_memset(fragments, 0, sizeof(fragments)); |
| }; |
| |
| BufFragStatusClass::status_t AddFragment(const BufferFragment& frag, BufferState* in_buffer_state, |
| int32 location_offset = max_frags) |
| { |
| if (num_fragments > max_frags) |
| { |
| return BufFragStatusClass::TOO_MANY_FRAGS; |
| } |
| if (frag.ptr == NULL) |
| { |
| return BufFragStatusClass::EMPTY_FRAGMENT; |
| } |
| |
| if (location_offset >= 0 && location_offset < (int32) num_fragments) |
| { |
| if (fragments[location_offset].ptr) |
| { |
| // make room for the new fragment |
| oscl_memmove(fragments + location_offset + 1, fragments + location_offset, |
| (num_fragments - location_offset)*sizeof(BufferFragment)); |
| oscl_memmove(buffer_states + location_offset + 1, buffer_states + location_offset, |
| (num_fragments - location_offset)*sizeof(BufferState*)); |
| ++num_fragments; /* increment the number of fragments if a move |
| * is necessary. If the location was empty, then |
| * has already been reserved and counted. |
| */ |
| } |
| fragments[location_offset] = frag; |
| buffer_states[location_offset] = in_buffer_state; |
| if (in_buffer_state) in_buffer_state->increment_refcnt(); |
| length += frag.len; |
| return BufFragStatusClass::BFG_SUCCESS; |
| } |
| |
| // append the new fragment to the end |
| fragments[num_fragments] = frag; |
| buffer_states[num_fragments++] = in_buffer_state; |
| length += frag.len; |
| if (in_buffer_state) in_buffer_state->increment_refcnt(); |
| return BufFragStatusClass::BFG_SUCCESS; |
| }; |
| |
| BufferFragment fragments[max_frags]; |
| BufferState* buffer_states[max_frags]; |
| ChainClass* next; |
| uint32 num_fragments; |
| uint32 length; |
| }; |
| |
| template <class ChainClass, uint32 max_frags> inline BufferFragment * BufFragGroup<ChainClass, max_frags> :: GetFragment(const int32 idx) |
| { |
| if (idx < (int)num_fragments && idx >= 0) |
| { |
| return & fragments[idx]; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| template <class ChainClass, uint32 max_frags> inline BufferState * BufFragGroup<ChainClass, max_frags> :: GetBufferState(const int32 idx) |
| { |
| if (idx < (int)num_fragments && idx >= 0) |
| { |
| return buffer_states[idx]; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| |
| template <class ChainClass, uint32 max_frags, uint32 local_bufsize> class MediaData : |
| public BufFragGroup<ChainClass, max_frags> |
| { |
| |
| public: |
| MediaData(): timestamp(0), available_localbuf(local_bufsize), num_reserved_fragments(0) {}; |
| |
| virtual ~MediaData() {} |
| |
| uint32 GetLocalBufsize() const |
| { |
| return local_bufsize; |
| }; |
| MediaTimestamp GetTimestamp() const |
| { |
| return timestamp; |
| }; |
| void SetTimestamp(MediaTimestamp in_timestamp) |
| { |
| timestamp = in_timestamp; |
| }; |
| uint32 GetAvailableBufferSize() const |
| { |
| return available_localbuf; |
| }; |
| |
| |
| |
| // The input should be initialized so that the fragment length is the |
| // request size. The returned value will have a non-NULL pointer if the |
| // request could be fulfilled. |
| MediaStatusClass::status_t GetLocalFragment(BufferFragment& fragment) |
| { |
| if (fragment.len > available_localbuf) |
| { |
| fragment.ptr = NULL; |
| fragment.len = available_localbuf; |
| return MediaStatusClass::NOT_ENOUGH_SPACE; |
| } |
| |
| fragment.ptr = localbuf + (local_bufsize - available_localbuf); |
| available_localbuf -= fragment.len; |
| return MediaStatusClass::BFG_SUCCESS; |
| }; |
| |
| virtual void Clear() |
| { |
| for (uint ii = 0 ; ii < this->num_fragments; ++ii) |
| { |
| if (this->buffer_states[ii]) |
| { |
| this->buffer_states[ii]->decrement_refcnt(); |
| } |
| } |
| this->num_fragments = 0; |
| this->length = 0; |
| oscl_memset(this->buffer_states, 0, sizeof(this->buffer_states)); |
| oscl_memset(this->fragments, 0, sizeof(this->fragments)); |
| this->available_localbuf = local_bufsize; |
| }; |
| |
| |
| bool IsLocalData(const OsclMemoryFragment& frag) const |
| { |
| if (frag.ptr == NULL) |
| return true; |
| if ((uint8 *)frag.ptr >= localbuf) |
| { |
| if (((uint8 *)frag.ptr) + frag.len < localbuf + local_bufsize) |
| { |
| return true; |
| } |
| return false; |
| } |
| return false; |
| } |
| |
| int GetMediaSize() const |
| { |
| int num_reserved = 0; |
| for (int ii = 0; ii < num_reserved_fragments; ii++) |
| num_reserved += this->fragments[ii].len; |
| |
| return (this->length - num_reserved); |
| } |
| |
| BufferFragment * GetMediaFragment(const uint32 idx) |
| { |
| uint32 tmp = idx + this->num_reserved_fragments; |
| if (tmp > this->num_fragments) |
| { |
| return NULL; |
| } |
| else |
| { |
| return & this->fragments[tmp]; |
| } |
| } |
| |
| uint32 GetNumMediaFrags(const uint32 idx) const |
| { |
| if (this->num_fragments >= this->num_reserved_fragments) |
| return this->num_fragments - this->num_reserved_fragments; |
| else return 0; |
| } |
| |
| protected: |
| // This function copies the fragment data to the local buffer |
| MediaStatusClass::status_t AddLocalFragment(const BufferFragment& frag, |
| int32 location_offset) |
| { |
| |
| if (this->num_fragments > max_frags) |
| { |
| return MediaStatusClass::TOO_MANY_FRAGS; |
| } |
| |
| if (frag.ptr == NULL || frag.len == 0) |
| { |
| return MediaStatusClass::EMPTY_FRAGMENT; |
| } |
| |
| // see if there is enough room in the local buffer |
| if (frag.len > available_localbuf) |
| { |
| return MediaStatusClass::NOT_ENOUGH_SPACE; |
| } |
| |
| // get the fragment |
| BufferFragment local_fragment; |
| local_fragment.len = frag.len; |
| local_fragment.ptr = localbuf + (local_bufsize - available_localbuf); |
| available_localbuf -= frag.len; |
| this->length += frag.len; |
| |
| oscl_memcpy(local_fragment.ptr, frag.ptr, frag.len*sizeof(uint8)); |
| |
| if (location_offset >= 0 && location_offset < (int32) this->num_fragments) |
| { |
| if (this->fragments[location_offset].ptr) |
| { |
| // make room for the new fragment |
| oscl_memmove(this->fragments + location_offset + 1, this->fragments + location_offset, |
| (this->num_fragments - location_offset)*sizeof(BufferFragment)); |
| oscl_memmove(this->buffer_states + location_offset + 1, this->buffer_states + location_offset, |
| (this->num_fragments - location_offset)*sizeof(BufferState*)); |
| ++this->num_fragments; /* increment the number of fragments if a move |
| * is necessary. If the location was empty, then |
| * has already been reserved and counted. |
| */ |
| } |
| this->fragments[location_offset] = local_fragment; |
| this->buffer_states[location_offset] = NULL; |
| return MediaStatusClass::BFG_SUCCESS; |
| } |
| |
| // append the new fragment to the end |
| this->fragments[this->num_fragments] = local_fragment; |
| this->buffer_states[this->num_fragments++] = NULL; |
| return MediaStatusClass::BFG_SUCCESS; |
| }; |
| |
| MediaTimestamp timestamp; |
| uint8 localbuf[local_bufsize]; |
| uint32 available_localbuf; |
| |
| int num_reserved_fragments; |
| }; |
| |
| #endif |
| |
| /*! @} */ |