libavcodec/avpacket.c
Go to the documentation of this file.
00001 /*
00002  * AVPacket functions for libavcodec
00003  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include "avcodec.h"
00023 #include "internal.h"
00024 #include "libavutil/avassert.h"
00025 #include "bytestream.h"
00026 
00027 void av_destruct_packet_nofree(AVPacket *pkt)
00028 {
00029     pkt->data = NULL; pkt->size = 0;
00030     pkt->side_data       = NULL;
00031     pkt->side_data_elems = 0;
00032 }
00033 
00034 void ff_packet_free_side_data(AVPacket *pkt)
00035 {
00036     int i;
00037     for (i = 0; i < pkt->side_data_elems; i++)
00038         av_free(pkt->side_data[i].data);
00039     av_freep(&pkt->side_data);
00040     pkt->side_data_elems = 0;
00041 }
00042 
00043 void av_destruct_packet(AVPacket *pkt)
00044 {
00045     av_free(pkt->data);
00046     pkt->data = NULL; pkt->size = 0;
00047 
00048     ff_packet_free_side_data(pkt);
00049 }
00050 
00051 void av_init_packet(AVPacket *pkt)
00052 {
00053     pkt->pts   = AV_NOPTS_VALUE;
00054     pkt->dts   = AV_NOPTS_VALUE;
00055     pkt->pos   = -1;
00056     pkt->duration = 0;
00057     pkt->convergence_duration = 0;
00058     pkt->flags = 0;
00059     pkt->stream_index = 0;
00060     pkt->destruct= NULL;
00061     pkt->side_data       = NULL;
00062     pkt->side_data_elems = 0;
00063 }
00064 
00065 int av_new_packet(AVPacket *pkt, int size)
00066 {
00067     uint8_t *data= NULL;
00068     if((unsigned)size < (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
00069         data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
00070     if (data){
00071         memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00072     }else
00073         size=0;
00074 
00075     av_init_packet(pkt);
00076     pkt->data = data;
00077     pkt->size = size;
00078     pkt->destruct = av_destruct_packet;
00079     if(!data)
00080         return AVERROR(ENOMEM);
00081     return 0;
00082 }
00083 
00084 void av_shrink_packet(AVPacket *pkt, int size)
00085 {
00086     if (pkt->size <= size) return;
00087     pkt->size = size;
00088     memset(pkt->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00089 }
00090 
00091 int av_grow_packet(AVPacket *pkt, int grow_by)
00092 {
00093     void *new_ptr;
00094     av_assert0((unsigned)pkt->size <= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE);
00095     if (!pkt->size)
00096         return av_new_packet(pkt, grow_by);
00097     if ((unsigned)grow_by > INT_MAX - (pkt->size + FF_INPUT_BUFFER_PADDING_SIZE))
00098         return -1;
00099     new_ptr = av_realloc(pkt->data, pkt->size + grow_by + FF_INPUT_BUFFER_PADDING_SIZE);
00100     if (!new_ptr)
00101         return AVERROR(ENOMEM);
00102     pkt->data = new_ptr;
00103     pkt->size += grow_by;
00104     memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00105     return 0;
00106 }
00107 
00108 #define DUP_DATA(dst, src, size, padding) \
00109     do { \
00110         void *data; \
00111         if (padding) { \
00112             if ((unsigned)(size) > (unsigned)(size) + FF_INPUT_BUFFER_PADDING_SIZE) \
00113                 goto failed_alloc; \
00114             data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); \
00115         } else { \
00116             data = av_malloc(size); \
00117         } \
00118         if (!data) \
00119             goto failed_alloc; \
00120         memcpy(data, src, size); \
00121         if (padding) \
00122             memset((uint8_t*)data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); \
00123         dst = data; \
00124     } while(0)
00125 
00126 int av_dup_packet(AVPacket *pkt)
00127 {
00128     AVPacket tmp_pkt;
00129 
00130     if (((pkt->destruct == av_destruct_packet_nofree) || (pkt->destruct == NULL)) && pkt->data) {
00131         tmp_pkt = *pkt;
00132 
00133         pkt->data      = NULL;
00134         pkt->side_data = NULL;
00135         DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1);
00136         pkt->destruct = av_destruct_packet;
00137 
00138         if (pkt->side_data_elems) {
00139             int i;
00140 
00141             DUP_DATA(pkt->side_data, tmp_pkt.side_data,
00142                      pkt->side_data_elems * sizeof(*pkt->side_data), 0);
00143             memset(pkt->side_data, 0, pkt->side_data_elems * sizeof(*pkt->side_data));
00144             for (i = 0; i < pkt->side_data_elems; i++) {
00145                 DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
00146                          pkt->side_data[i].size, 1);
00147             }
00148         }
00149     }
00150     return 0;
00151 failed_alloc:
00152     av_destruct_packet(pkt);
00153     return AVERROR(ENOMEM);
00154 }
00155 
00156 void av_free_packet(AVPacket *pkt)
00157 {
00158     if (pkt) {
00159         if (pkt->destruct) pkt->destruct(pkt);
00160         pkt->data = NULL; pkt->size = 0;
00161         pkt->side_data       = NULL;
00162         pkt->side_data_elems = 0;
00163     }
00164 }
00165 
00166 uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
00167                                  int size)
00168 {
00169     int elems = pkt->side_data_elems;
00170 
00171     if ((unsigned)elems + 1 > INT_MAX / sizeof(*pkt->side_data))
00172         return NULL;
00173     if ((unsigned)size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
00174         return NULL;
00175 
00176     pkt->side_data = av_realloc(pkt->side_data, (elems + 1) * sizeof(*pkt->side_data));
00177     if (!pkt->side_data)
00178         return NULL;
00179 
00180     pkt->side_data[elems].data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
00181     if (!pkt->side_data[elems].data)
00182         return NULL;
00183     pkt->side_data[elems].size = size;
00184     pkt->side_data[elems].type = type;
00185     pkt->side_data_elems++;
00186 
00187     return pkt->side_data[elems].data;
00188 }
00189 
00190 uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
00191                                  int *size)
00192 {
00193     int i;
00194 
00195     for (i = 0; i < pkt->side_data_elems; i++) {
00196         if (pkt->side_data[i].type == type) {
00197             if (size)
00198                 *size = pkt->side_data[i].size;
00199             return pkt->side_data[i].data;
00200         }
00201     }
00202     return NULL;
00203 }
00204 
00205 #define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL
00206 
00207 int av_packet_merge_side_data(AVPacket *pkt){
00208     if(pkt->side_data_elems){
00209         int i;
00210         uint8_t *p;
00211         uint64_t size= pkt->size + 8LL + FF_INPUT_BUFFER_PADDING_SIZE;
00212         AVPacket old= *pkt;
00213         for (i=0; i<old.side_data_elems; i++) {
00214             size += old.side_data[i].size + 5LL;
00215         }
00216         if (size > INT_MAX)
00217             return AVERROR(EINVAL);
00218         p = av_malloc(size);
00219         if (!p)
00220             return AVERROR(ENOMEM);
00221         pkt->data = p;
00222         pkt->destruct = av_destruct_packet;
00223         pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE;
00224         bytestream_put_buffer(&p, old.data, old.size);
00225         for (i=old.side_data_elems-1; i>=0; i--) {
00226             bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size);
00227             bytestream_put_be32(&p, old.side_data[i].size);
00228             *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128);
00229         }
00230         bytestream_put_be64(&p, FF_MERGE_MARKER);
00231         av_assert0(p-pkt->data == pkt->size);
00232         memset(p, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00233         av_free_packet(&old);
00234         pkt->side_data_elems = 0;
00235         pkt->side_data = NULL;
00236         return 1;
00237     }
00238     return 0;
00239 }
00240 
00241 int av_packet_split_side_data(AVPacket *pkt){
00242     if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){
00243         int i;
00244         unsigned int size;
00245         uint8_t *p;
00246 
00247         p = pkt->data + pkt->size - 8 - 5;
00248         for (i=1; ; i++){
00249             size = AV_RB32(p);
00250             if (size>INT_MAX || p - pkt->data <= size)
00251                 return 0;
00252             if (p[4]&128)
00253                 break;
00254             p-= size+5;
00255         }
00256 
00257         pkt->side_data = av_malloc(i * sizeof(*pkt->side_data));
00258         if (!pkt->side_data)
00259             return AVERROR(ENOMEM);
00260 
00261         p= pkt->data + pkt->size - 8 - 5;
00262         for (i=0; ; i++){
00263             size= AV_RB32(p);
00264             av_assert0(size<=INT_MAX && p - pkt->data > size);
00265             pkt->side_data[i].data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
00266             pkt->side_data[i].size = size;
00267             pkt->side_data[i].type = p[4]&127;
00268             if (!pkt->side_data[i].data)
00269                 return AVERROR(ENOMEM);
00270             memcpy(pkt->side_data[i].data, p-size, size);
00271             pkt->size -= size + 5;
00272             if(p[4]&128)
00273                 break;
00274             p-= size+5;
00275         }
00276         pkt->size -= 8;
00277         pkt->side_data_elems = i+1;
00278         return 1;
00279     }
00280     return 0;
00281 }