static uint8_t fatfs_dir_buf_add(FATFS_INFO * fatfs, TSK_INUM_T par_inum, TSK_INUM_T dir_inum) { size_t q; for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == dir_inum) { return 0; } } // make sure we have room if (fatfs->dir_buf_next == fatfs->dir_buf_size) { fatfs->dir_buf_size += 256; if ((fatfs->dir_buf = (TSK_INUM_T *) tsk_realloc(fatfs->dir_buf, fatfs->dir_buf_size * sizeof(TSK_INUM_T))) == NULL) { return 1; } if ((fatfs->par_buf = (TSK_INUM_T *) tsk_realloc(fatfs->par_buf, fatfs->dir_buf_size * sizeof(TSK_INUM_T))) == NULL) { return 1; } } //add them fatfs->dir_buf[fatfs->dir_buf_next] = dir_inum; fatfs->par_buf[fatfs->dir_buf_next] = par_inum; fatfs->dir_buf_next++; return 0; }
/**@ingroup tsk_buffer_group * Appends new data to the buffer. * @param self The buffer to append to. The buffer should be created using @ref tsk_buffer_create or @ref tsk_buffer_create_null. * @param format A string with embedded tag to be substituted. * @param ... List of parameters. * @retval Zero if succeed and non-zero error code otherwise. * @sa @ref tsk_buffer_append. * * @code * tsk_buffer_t* buffer = tsk_buffer_create_null(); * tsk_buffer_append_2(buffer, "str1=%s, c1=%c and val1=%x", "str1", 'c', 0x2554); * printf(TSK_BUFFER_TO_STRING(buffer)); * TSK_OBJECT_SAFE_FREE(buffer); * @endcode */ int tsk_buffer_append_2(tsk_buffer_t* self, const char* format, ...) { /* * I suppose that sizeof(char) = 1-byte */ int len = 0; va_list ap; char *buffer; tsk_size_t oldsize; va_list ap2; if(!self){ return -1; } oldsize = self->size; buffer = (char*)TSK_BUFFER_DATA(self); /* initialize variable arguments (needed for 64bit platforms where vsnprintf will change the va_list) */ va_start(ap, format); va_start(ap2, format); /* compute destination len for windows mobile */ #if defined(_WIN32_WCE) { int n; len = (tsk_strlen(format)*2); buffer = (char*)tsk_realloc(buffer, (oldsize+len)); for(;;){ if( (n = vsnprintf((char*)(buffer + oldsize), len, format, ap)) >= 0 && (n<=len) ){ len = n; break; } else{ len += 10; buffer = (char*)tsk_realloc(buffer, (oldsize+len)); } } } #else len = vsnprintf(tsk_null, 0, format, ap); buffer = (char*)tsk_realloc(buffer, oldsize+len+1); vsnprintf((buffer + oldsize), len #if !defined(_MSC_VER) || defined(__GNUC__) +1 #endif , format, ap2); #endif /* reset variable arguments */ va_end(ap); va_end(ap2); self->data = buffer; self->size = (oldsize+len); return 0; }
/** \internal * Copy the contents of a TSK_FS_NAME structure to another * structure. * @param a_fs_name_to Destination structure to copy to * @param a_fs_name_from Source structure to copy from * @returns 1 on error */ uint8_t tsk_fs_name_copy(TSK_FS_NAME * a_fs_name_to, const TSK_FS_NAME * a_fs_name_from) { if ((a_fs_name_to == NULL) || (a_fs_name_from == NULL)) return 1; /* If the source has a full name, copy it */ if (a_fs_name_from->name) { // make sure there is enough space if (strlen(a_fs_name_from->name) >= a_fs_name_to->name_size) { a_fs_name_to->name_size = strlen(a_fs_name_from->name) + 16; a_fs_name_to->name = (char *) tsk_realloc(a_fs_name_to->name, a_fs_name_to->name_size); if (a_fs_name_to->name == NULL) return 1; } strncpy(a_fs_name_to->name, a_fs_name_from->name, a_fs_name_to->name_size); } else { if (a_fs_name_to->name_size > 0) a_fs_name_to->name[0] = '\0'; else a_fs_name_to->name = NULL; } // copy the short name, if one exists if (a_fs_name_from->shrt_name) { if (strlen(a_fs_name_from->shrt_name) >= a_fs_name_to->shrt_name_size) { a_fs_name_to->shrt_name_size = strlen(a_fs_name_from->shrt_name) + 16; a_fs_name_to->shrt_name = (char *) tsk_realloc(a_fs_name_to->shrt_name, a_fs_name_to->shrt_name_size); if (a_fs_name_to->shrt_name == NULL) return 1; } strncpy(a_fs_name_to->shrt_name, a_fs_name_from->shrt_name, a_fs_name_to->shrt_name_size); } else { if (a_fs_name_to->shrt_name_size > 0) a_fs_name_to->shrt_name[0] = '\0'; else a_fs_name_to->shrt_name = NULL; } a_fs_name_to->meta_addr = a_fs_name_from->meta_addr; a_fs_name_to->meta_seq = a_fs_name_from->meta_seq; a_fs_name_to->par_addr = a_fs_name_from->par_addr; a_fs_name_to->type = a_fs_name_from->type; a_fs_name_to->flags = a_fs_name_from->flags; return 0; }
static tsk_size_t tdav_codec_ilbc_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tdav_codec_ilbc_t* ilbc = (tdav_codec_ilbc_t*)self; int k; if(!self || !in_data || !in_size || !out_data){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } /* convert signal to float */ for(k=0; k<ilbc->encoder.blockl; k++){ ilbc->encblock[k] = (float)((short*)in_data)[k]; } /* allocate new buffer if needed */ if((int)*out_max_size <ilbc->encoder.no_of_bytes){ if(!(*out_data = tsk_realloc(*out_data, ilbc->encoder.no_of_bytes))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); *out_max_size = 0; return 0; } *out_max_size = ilbc->encoder.no_of_bytes; } /* do the actual encoding */ iLBC_encode(*out_data, ilbc->encblock, &ilbc->encoder); return ilbc->encoder.no_of_bytes; }
tsk_size_t tdav_codec_speex_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tdav_codec_speex_t* speex = (tdav_codec_speex_t*)self; tsk_size_t outsize = 0; if(!self || !in_data || !in_size || !out_data){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } speex_bits_reset(&speex->encoder.bits); speex_encode_int(speex->encoder.state, (spx_int16_t*)in_data, &speex->encoder.bits); if(*out_max_size <speex->encoder.size){ if((*out_data = tsk_realloc(*out_data, speex->encoder.size))){ *out_max_size = speex->encoder.size; } else{ *out_max_size = 0; return 0; } } outsize = speex_bits_write(&speex->encoder.bits, *out_data, speex->encoder.size/2); return outsize; }
tsk_size_t tdav_codec_gsm_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tsk_size_t out_size; tdav_codec_gsm_t* gsm = (tdav_codec_gsm_t*)self; if(!self || !in_data || !in_size || !out_data) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } out_size = ((in_size / (TMEDIA_CODEC_PCM_FRAME_SIZE(self) * sizeof(short))) * TDAV_GSM_FRAME_SIZE); /* allocate new buffer if needed */ if(*out_max_size <out_size) { if(!(*out_data = tsk_realloc(*out_data, out_size))) { TSK_DEBUG_ERROR("Failed to allocate new buffer"); *out_max_size = 0; return 0; } *out_max_size = out_size; } gsm_encode(gsm->encoder, (gsm_signal*)in_data, (gsm_byte*)*out_data); return out_size; }
/**@ingroup tsk_buffer_group * Appends data to the buffer. * @param self The buffer to append to. The buffer should be created using @ref tsk_buffer_create or @ref tsk_buffer_create_null. * @param data The data to append to the buffer. * @param size The size of the @a data to append. * @retval Zero if succeed and non-zero error code otherwise. * @sa @ref tsk_buffer_append_2. * * @code * tsk_buffer_t* buffer = tsk_buffer_create_null(); * tsk_buffer_append(buffer, "doubango", tsk_strlen("doubango")); * printf(TSK_BUFFER_TO_STRING(buffer)); * TSK_OBJECT_SAFE_FREE(buffer); * @endcode */ int tsk_buffer_append(tsk_buffer_t* self, const void* data, tsk_size_t size) { if(self && size){ tsk_size_t oldsize = self->size; tsk_size_t newsize = oldsize + size; if(oldsize){ self->data = tsk_realloc(self->data, newsize); } else{ self->data = tsk_calloc(size, sizeof(uint8_t)); } if(self->data){ if(data){ memcpy((void*)(TSK_BUFFER_TO_U8(self) + oldsize), data, size); } self->size = newsize; return 0; } } else{ TSK_DEBUG_ERROR("Invalid parameter"); } return -1; }
static tsk_size_t tdav_codec_g729ab_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tsk_size_t ex_size, out_size = 0; tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self; int i, frame_count = (in_size / 160); if(!self || !in_data || !in_size || !out_data || (in_size % 160)){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } ex_size = (frame_count * 10); // allocate new buffer if needed if(*out_max_size <ex_size){ if(!(*out_data = tsk_realloc(*out_data, ex_size))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); *out_max_size = 0; return 0; } *out_max_size = ex_size; } for(i=0; i<frame_count; i++){ extern int16_t *new_speech; if(g729a->encoder.frame == 32767){ g729a->encoder.frame = 256; } else{ g729a->encoder.frame++; } memcpy(new_speech, &((uint8_t*)in_data)[i*L_FRAME*sizeof(int16_t)], sizeof(int16_t)*L_FRAME); Pre_Process(new_speech, L_FRAME); Coder_ld8a(g729a->encoder.prm, g729a->encoder.frame, g729a->encoder.vad_enable); prm2bits_ld8k(g729a->encoder.prm, g729a->encoder.serial); if(g729a->encoder.serial[1] == RATE_8000){ pack_G729(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]); out_size += 10; } else if(g729a->encoder.serial[1] == RATE_SID_OCTET){ pack_SID(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]); out_size += 2; } else{ // RATE_0 //TSK_DEBUG_INFO("G729_RATE_0 - Not transmitted"); if (!g729a->encoder.vad_enable) { // silence memset(&((uint8_t*)(*out_data))[out_size], 0, 10); out_size += 10; } } } return out_size; }
tsk_size_t tdav_codec_gsm_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { tsk_size_t out_size; int ret; tdav_codec_gsm_t* gsm = (tdav_codec_gsm_t*)self; if(!self || !in_data || !in_size || !out_data || (in_size % TDAV_GSM_FRAME_SIZE)){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } out_size = (in_size / TDAV_GSM_FRAME_SIZE) * (TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_DECODING(self) * sizeof(short)); /* allocate new buffer if needed */ if(*out_max_size <out_size){ if(!(*out_data = tsk_realloc(*out_data, out_size))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); *out_max_size = 0; return 0; } *out_max_size = out_size; } ret = gsm_decode(gsm->decoder, (gsm_byte*)in_data, (gsm_signal*)*out_data); return out_size; }
/** \internal * Make the buffer in the FS_DIR structure larger. * * @param a_fs_dir Structure to enhance * @param a_cnt target number of FS_DENT entries to fit in * @returns 1 on error and 0 on success */ uint8_t tsk_fs_dir_realloc(TSK_FS_DIR * a_fs_dir, size_t a_cnt) { size_t prev_cnt, i; if ((a_fs_dir == NULL) || (a_fs_dir->tag != TSK_FS_DIR_TAG)) return 1; if (a_fs_dir->names_alloc >= a_cnt) return 0; prev_cnt = a_fs_dir->names_alloc; a_fs_dir->names_alloc = a_cnt; if ((a_fs_dir->names = (TSK_FS_NAME *) tsk_realloc((void *) a_fs_dir->names, sizeof(TSK_FS_NAME) * a_fs_dir->names_alloc)) == NULL) { return 1; } memset(&a_fs_dir->names[prev_cnt], 0, (a_cnt - prev_cnt) * sizeof(TSK_FS_NAME)); for (i = prev_cnt; i < a_cnt; i++) { a_fs_dir->names[i].tag = TSK_FS_NAME_TAG; } return 0; }
/** \internal * Extend the number of addresses in the map buffer. * @param map map entry to extend * @returns 1 on error and 0 otherwise */ static uint8_t ntfs_orphan_map_extend(NTFS_PAR_MAP * map) { map->alloc_cnt += 8; if ((map->addrs = (TSK_INUM_T *) tsk_realloc(map->addrs, sizeof(TSK_INUM_T) * map->alloc_cnt)) == NULL) return 1; return 0; }
/** * \internal * Resize an existing TSK_FS_META structure -- changes the number of * block pointers. * * @param fs_meta Structure to resize * @param a_buf_len Size of file system specific data that is used to store references to file content * @return NULL on error */ TSK_FS_META * tsk_fs_meta_realloc(TSK_FS_META * a_fs_meta, size_t a_buf_len) { if (a_fs_meta->content_len != a_buf_len) { a_fs_meta->content_len = a_buf_len; a_fs_meta->content_ptr = tsk_realloc((char *) a_fs_meta->content_ptr, a_buf_len); if (a_fs_meta->content_ptr == NULL) { return NULL; } } return (a_fs_meta); }
/** * \ingroup baselib * Push a value to the top of TSK_STACK. * @param a_tsk_stack Pointer to stack to push onto * @param a_val Value to push on * @returns 1 on error */ uint8_t tsk_stack_push(TSK_STACK * a_tsk_stack, uint64_t a_val) { if (a_tsk_stack->top == a_tsk_stack->len) { a_tsk_stack->len += 64; if ((a_tsk_stack->vals = (uint64_t *) tsk_realloc((char *) a_tsk_stack->vals, a_tsk_stack->len * sizeof(uint64_t))) == NULL) { return 1; } } a_tsk_stack->vals[a_tsk_stack->top++] = a_val; return 0; }
/**@ingroup tsk_string_group */ int tsk_sprintf_2(char** str, const char* format, va_list* ap) { int len = 0; va_list ap2; /* free previous value */ if(*str){ tsk_free((void**)str); } /* needed for 64bit platforms where vsnprintf will change the va_list */ tsk_va_copy(ap2, *ap); /* compute destination len for windows mobile */ #if defined(_WIN32_WCE) { int n; len = (tsk_strlen(format)*2); *str = (char*)tsk_calloc(1, len+1); for(;;){ if( (n = vsnprintf(*str, len, format, *ap)) >= 0 && (n<len) ){ len = n; goto done; } else{ len += 10; *str = tsk_realloc(*str, len+1); } } done: (*str)[len] = '\0'; } #else len = vsnprintf(0, 0, format, *ap); *str = (char*)tsk_calloc(1, len+1); vsnprintf(*str, len #if !defined(_MSC_VER) || defined(__GNUC__) +1 #endif , format, ap2); #endif va_end(ap2); return len; }
static tsk_size_t tdav_codec_opus_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { tdav_codec_opus_t* opus = (tdav_codec_opus_t*)self; int frame_size; const trtp_rtp_header_t* rtp_hdr = proto_hdr; if(!self || !in_data || !in_size || !out_data) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } if(!opus->decoder.inst) { TSK_DEBUG_ERROR("Decoder not ready"); return 0; } /* Packet loss? */ if(opus->decoder.last_seq != (rtp_hdr->seq_num - 1) && opus->decoder.last_seq) { if(opus->decoder.last_seq == rtp_hdr->seq_num) { // Could happen on some stupid emulators //TSK_DEBUG_INFO("Packet duplicated, seq_num=%d", rtp_hdr->seq_num); return 0; } TSK_DEBUG_INFO("[Opus] Packet loss, seq_num=%d", rtp_hdr->seq_num); opus_decode(opus->decoder.inst, tsk_null/*packet loss*/, (opus_int32)0, opus->decoder.buff, TDAV_OPUS_MAX_FRAME_SIZE_IN_SAMPLES, opus->decoder.fec_enabled); } opus->decoder.last_seq = rtp_hdr->seq_num; frame_size = opus_decode(opus->decoder.inst, (const unsigned char *)in_data, (opus_int32)in_size, opus->decoder.buff, TDAV_OPUS_MAX_FRAME_SIZE_IN_SAMPLES, opus->decoder.fec_enabled ? 1 : 0); if(frame_size > 0) { tsk_size_t frame_size_inbytes = (frame_size << 1); if(*out_max_size < frame_size_inbytes) { if(!(*out_data = tsk_realloc(*out_data, frame_size_inbytes))) { TSK_DEBUG_ERROR("Failed to allocate new buffer"); *out_max_size = 0; return 0; } *out_max_size = frame_size_inbytes; } memcpy(*out_data, opus->decoder.buff, frame_size_inbytes); return frame_size_inbytes; } else { return 0; } }
/**@ingroup tsk_string_group */ void tsk_strncat(char** destination, const char* source, tsk_size_t n) { tsk_size_t index = 0; tsk_size_t tsk_size_to_cat = (n > tsk_strlen(source)) ? tsk_strlen(source) : n; if(!source || !n){ return; } if(!*destination){ *destination = (char*)tsk_malloc(tsk_size_to_cat+1); strncpy(*destination, source, tsk_size_to_cat+1); }else{ index = tsk_strlen(*destination); *destination = tsk_realloc(*destination, index + tsk_size_to_cat+1); strncpy(((*destination)+index), source, tsk_size_to_cat+1); } (*destination)[index + tsk_size_to_cat] = '\0'; }
/** * \internal * returns 1 on error */ uint8_t tsk_fs_name_realloc(TSK_FS_NAME * fs_name, size_t namelen) { if ((fs_name == NULL) || (fs_name->tag != TSK_FS_NAME_TAG)) return 1; if (fs_name->name_size >= namelen) return 0; fs_name->name = (char *) tsk_realloc(fs_name->name, namelen + 1); if (fs_name->name == NULL) { fs_name->name_size = 0; return 1; } fs_name->type = TSK_FS_NAME_TYPE_UNDEF; fs_name->name_size = namelen; return 0; }
/**@ingroup tsk_buffer_group * Reallocates the buffer. * @param self The buffer to realloc. * @param size The new size. * @retval Zero if succeed and non-zero error code otherwise. */ int tsk_buffer_realloc(tsk_buffer_t* self, tsk_size_t size) { if(self) { if(size == 0){ return tsk_buffer_cleanup(self); } if(self->size == 0){ // first time? self->data = tsk_calloc(size, sizeof(uint8_t)); } else if(self->size != size){ // only realloc if different sizes self->data = tsk_realloc(self->data, size); } self->size = size; return 0; } return -1; }
/** * Add a name to an existing FS_DATA structure. Will reallocate * space for the name if needed. * * @param fs_attr Structure to add name to * @param name UTF-8 name to add * * @return 1 on error and 0 on success */ static uint8_t fs_attr_put_name(TSK_FS_ATTR * fs_attr, const char *name) { if ((name == NULL) || (strlen(name) == 0)) { if (fs_attr->name_size > 0) { free(fs_attr->name); fs_attr->name_size = 0; } fs_attr->name = NULL; return 0; } if (fs_attr->name_size < (strlen(name) + 1)) { fs_attr->name = tsk_realloc(fs_attr->name, strlen(name) + 1); if (fs_attr->name == NULL) return 1; fs_attr->name_size = strlen(name) + 1; } strncpy(fs_attr->name, name, fs_attr->name_size); return 0; }
tsk_size_t tdav_codec_speex_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { int ret; tsk_size_t out_size = 0; tdav_codec_speex_t* speex = (tdav_codec_speex_t*)self; if(!self || !in_data || !in_size || !out_data){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } // initializes the bit-stream speex_bits_read_from(&speex->decoder.bits, (char*)in_data, in_size); do{ // performs decode() if((ret = speex_decode_int(speex->decoder.state, &speex->decoder.bits, speex->decoder.buffer))){ TSK_DEBUG_ERROR("Failed to decode the buffer. retcode=%d", ret); break; } if(*out_max_size <(out_size + speex->decoder.size)){ if((*out_data = tsk_realloc(*out_data, (out_size + speex->decoder.size)))){ *out_max_size = (out_size + speex->decoder.size); } else{ *out_max_size = 0; return 0; } } // copy output buffer memcpy(&((uint8_t*)*out_data)[out_size], speex->decoder.buffer, speex->decoder.size); out_size += speex->decoder.size; } while(speex_bits_remaining(&speex->decoder.bits) >= 5); return out_size; }
/** * \internal * Copy resident data to an attribute. * * @param a_fs_attr Attribute to add data to (cannot be NULL) * @param name Name of the attribute to set * @param type Type of the attribute to set * @param id Id of the attribute to set * @param res_data Pointer to where resident data is located (data will * be copied from here into FS_DATA) * @param len Length of resident data * @return 1 on error and 0 on success */ uint8_t tsk_fs_attr_set_str(TSK_FS_FILE * a_fs_file, TSK_FS_ATTR * a_fs_attr, const char *name, TSK_FS_ATTR_TYPE_ENUM type, uint16_t id, void *res_data, size_t len) { if (a_fs_attr == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("Null fs_attr in tsk_fs_attr_set_str"); return 1; } a_fs_attr->fs_file = a_fs_file; a_fs_attr->flags = (TSK_FS_ATTR_INUSE | TSK_FS_ATTR_RES); a_fs_attr->type = type; a_fs_attr->id = id; a_fs_attr->nrd.compsize = 0; if (fs_attr_put_name(a_fs_attr, name)) { return 1; } if (a_fs_attr->rd.buf_size < len) { a_fs_attr->rd.buf = (uint8_t *) tsk_realloc((char *) a_fs_attr->rd.buf, len); if (a_fs_attr->rd.buf == NULL) return 1; a_fs_attr->rd.buf_size = len; } memset(a_fs_attr->rd.buf, 0, a_fs_attr->rd.buf_size); memcpy(a_fs_attr->rd.buf, res_data, len); a_fs_attr->size = len; return 0; }
static tsk_size_t tdav_codec_red_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tdav_codec_red_t *red = (tdav_codec_red_t *)self; tsk_size_t xsize = (in_size + 1); static const uint8_t __first_octet = 0x00; // F=1, PT=0. Up to the caller to update this first octet with the right PT. if(!red || !in_data || !in_size || !out_data || !out_max_size){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } if(*out_max_size < xsize){ if(!(*out_data = tsk_realloc(*out_data, xsize))){ TSK_DEBUG_ERROR("Failed to realloc data"); *out_max_size = 0; } *out_max_size = xsize; } ((uint8_t*)*out_data)[0] = __first_octet; memcpy(&((uint8_t*)*out_data)[1], in_data, in_size); return xsize; }
static tsk_size_t tdav_codec_opus_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { tdav_codec_opus_t* opus = (tdav_codec_opus_t*)self; opus_int32 ret; if(!self || !in_data || !in_size || !out_data) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } if(!opus->encoder.inst) { TSK_DEBUG_ERROR("Encoder not ready"); return 0; } // we're sure that the output (encoded) size cannot be higher than the input (raw) if(*out_max_size < in_size) { if(!(*out_data = tsk_realloc(*out_data, in_size))) { TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", in_size); *out_max_size = 0; return 0; } *out_max_size = in_size; } ret = opus_encode(opus->encoder.inst, (const opus_int16 *)in_data, (int)(in_size >> 1), (unsigned char *)*out_data, (opus_int32)*out_max_size); if(ret < 0) { TSK_DEBUG_ERROR("opus_encode() failed with error code = %d", ret); return 0; } return (tsk_size_t)ret; }
static int tdav_webrtc_denoise_open(tmedia_denoise_t* self, uint32_t frame_size, uint32_t sampling_rate) { tdav_webrtc_denoise_t *denoiser = (tdav_webrtc_denoise_t *)self; int ret; if(!denoiser){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(denoiser->AEC_inst || #if HAVE_SPEEX_DSP && PREFER_SPEEX_DENOISER denoiser->SpeexDenoiser_proc #else denoiser->NS_inst #endif ){ TSK_DEBUG_ERROR("Denoiser already initialized"); return -2; } denoiser->echo_tail = TSK_CLAMP(WEBRTC_MIN_ECHO_TAIL, TMEDIA_DENOISE(denoiser)->echo_tail, WEBRTC_MAX_ECHO_TAIL); TSK_DEBUG_INFO("echo_tail=%d", denoiser->echo_tail); denoiser->echo_skew = TMEDIA_DENOISE(denoiser)->echo_skew; denoiser->frame_size = frame_size; denoiser->sampling_rate = sampling_rate; // // AEC instance // if((ret = TDAV_WebRtcAec_Create(&denoiser->AEC_inst))){ TSK_DEBUG_ERROR("WebRtcAec_Create failed with error code = %d", ret); return ret; } if((ret = TDAV_WebRtcAec_Init(denoiser->AEC_inst, denoiser->sampling_rate, denoiser->sampling_rate))){ TSK_DEBUG_ERROR("WebRtcAec_Init failed with error code = %d", ret); return ret; } #if WEBRTC_AEC_AGGRESSIVE { AecConfig aecConfig; aecConfig.nlpMode = kAecNlpAggressive; aecConfig.skewMode = kAecTrue; aecConfig.metricsMode = kAecFalse; aecConfig.delay_logging = kAecFalse; if((ret = WebRtcAec_set_config(denoiser->AEC_inst, aecConfig))){ TSK_DEBUG_ERROR("WebRtcAec_set_config failed with error code = %d", ret); } } #endif // // Noise Suppression instance // if(TMEDIA_DENOISE(denoiser)->noise_supp_enabled){ #if HAVE_SPEEX_DSP && PREFER_SPEEX_DENOISER if((denoiser->SpeexDenoiser_proc = speex_preprocess_state_init(denoiser->frame_size, denoiser->sampling_rate))){ int i = 1; speex_preprocess_ctl(denoiser->SpeexDenoiser_proc, SPEEX_PREPROCESS_SET_DENOISE, &i); i = TMEDIA_DENOISE(denoiser)->noise_supp_level; speex_preprocess_ctl(denoiser->SpeexDenoiser_proc, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &i); } #else if((ret = TDAV_WebRtcNs_Create(&denoiser->NS_inst))){ TSK_DEBUG_ERROR("WebRtcNs_Create failed with error code = %d", ret); return ret; } if((ret = TDAV_WebRtcNs_Init(denoiser->NS_inst, denoiser->sampling_rate))){ TSK_DEBUG_ERROR("WebRtcNs_Init failed with error code = %d", ret); return ret; } #endif } // allocate temp buffer for record processing if(!(denoiser->temp_rec_out = tsk_realloc(denoiser->temp_rec_out, denoiser->frame_size * kSizeOfWord16))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); return -3; } TSK_DEBUG_INFO("WebRTC denoiser opened"); return ret; }
int tnet_tls_socket_recv(tnet_tls_socket_handle_t* self, void** data, tsk_size_t *size, tsk_bool_t *isEncrypted) { #if !HAVE_OPENSSL TSK_DEBUG_ERROR("You MUST enable OpenSSL"); return -200; #else int ret = -1; tsk_size_t read = 0; tsk_size_t to_read = *size; int rcount = TNET_TLS_RETRY_COUNT; tnet_tls_socket_t* socket = self; if(!self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_safeobj_lock(socket); *isEncrypted = SSL_is_init_finished(socket->ssl) ? tsk_false : tsk_true; /* SSL handshake has completed? */ if(*isEncrypted){ char* buffer[1024]; if((ret = SSL_read(socket->ssl, buffer, sizeof(buffer))) <= 0){ ret = SSL_get_error(socket->ssl, ret); if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){ ret = 0; } else{ TSK_DEBUG_ERROR("SSL_read failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); } *size = 0; } else{ *size = ret; ret = 0; } goto bail; } /* Read Application data */ ssl_read: if(rcount && ((ret = SSL_read(socket->ssl, (((uint8_t*)*data)+read), (int)to_read)) <= 0)){ ret = SSL_get_error(socket->ssl, ret); if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){ if(!(ret = tnet_sockfd_waitUntil(socket->fd, TNET_TLS_TIMEOUT, (ret == SSL_ERROR_WANT_WRITE)))){ rcount--; goto ssl_read; } } else if(SSL_ERROR_ZERO_RETURN){ /* connection closed: do nothing, the transport layer will be alerted. */ *size = 0; ret = 0; TSK_DEBUG_INFO("TLS connection closed."); } else{ TSK_DEBUG_ERROR("SSL_read failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); } } else if(ret >=0){ read += (tsk_size_t)ret; if((ret = SSL_pending(socket->ssl)) > 0){ void *ptr; to_read = ret; if((ptr = tsk_realloc(*data, (read + to_read)))){ *data = ptr; goto ssl_read; } } } bail: tsk_safeobj_unlock(socket); if(read){ *size = read; return 0; } else{ return ret; } #endif }
static int tdav_speex_jitterbuffer_put(tmedia_jitterbuffer_t* self, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr) { tdav_speex_jitterbuffer_t *jb = (tdav_speex_jitterbuffer_t *)self; const trtp_rtp_header_t* rtp_hdr; JitterBufferPacket jb_packet; static uint16_t seq_num = 0; if(!data || !data_size || !proto_hdr){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!jb->state){ TSK_DEBUG_ERROR("Invalid state"); return -2; } rtp_hdr = TRTP_RTP_HEADER(proto_hdr); jb_packet.user_data = 0; jb_packet.span = jb->frame_duration; jb_packet.len = jb->x_data_size; if(jb->x_data_size == data_size){ /* ptime match */ jb_packet.data = data; jb_packet.sequence = rtp_hdr->seq_num; jb_packet.timestamp = (rtp_hdr->seq_num * jb_packet.span); jitter_buffer_put(jb->state, &jb_packet); } else{ /* ptime mismatch */ tsk_size_t i; jb_packet.sequence = 0; // Ignore if((jb->buff.index + data_size) > jb->buff.size){ if(!(jb->buff.ptr = tsk_realloc(jb->buff.ptr, (jb->buff.index + data_size)))){ jb->buff.size = 0; jb->buff.index = 0; return 0; } jb->buff.size = (jb->buff.index + data_size); } memcpy(&jb->buff.ptr[jb->buff.index], data, data_size); jb->buff.index += data_size; if(jb->buff.index >= jb->x_data_size){ tsk_size_t copied = 0; for(i = 0; (i + jb->x_data_size) <= jb->buff.index; i += jb->x_data_size){ jb_packet.data = (char*)&jb->buff.ptr[i]; jb_packet.timestamp = (++jb->fake_seqnum * jb_packet.span);// reassembled pkt will have fake seqnum jitter_buffer_put(jb->state, &jb_packet); copied += jb->x_data_size; } if(copied == jb->buff.index){ // all copied jb->buff.index = 0; } else{ memmove(&jb->buff.ptr[0], &jb->buff.ptr[copied], (jb->buff.index - copied)); jb->buff.index -= copied; } } } return 0; }
static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { static UInt32 flagOne = 1; AudioStreamBasicDescription audioFormat; #define kOutputBus 0 tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; OSStatus status = noErr; if(!consumer || !codec || !codec->plugin){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!consumer->audioUnitHandle){ if(!(consumer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_CONSUMER(consumer)->session_id))){ TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_CONSUMER(consumer)->session_id); return -3; } } // enable status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flagOne, sizeof(flagOne)); if(status){ TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%d", (int32_t)status); return -4; } else { #if !TARGET_OS_IPHONE // strange: TARGET_OS_MAC is equal to '1' on Smulator UInt32 param; // disable input param = 0; status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(UInt32)); if(status != noErr){ TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); return -4; } // set default audio device param = sizeof(AudioDeviceID); AudioDeviceID outputDeviceID; status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, ¶m, &outputDeviceID); if(status != noErr){ TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed with status=%ld", (signed long)status); return -4; } // set the current device to the default input unit status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &outputDeviceID, sizeof(AudioDeviceID)); if(status != noErr){ TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status); return -4; } #endif TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); TSK_DEBUG_INFO("AudioUnit consumer: in.channels=%d, out.channles=%d, in.rate=%d, out.rate=%d, ptime=%d", TMEDIA_CONSUMER(consumer)->audio.in.channels, TMEDIA_CONSUMER(consumer)->audio.out.channels, TMEDIA_CONSUMER(consumer)->audio.in.rate, TMEDIA_CONSUMER(consumer)->audio.out.rate, TMEDIA_CONSUMER(consumer)->audio.ptime); audioFormat.mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate; audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioFormat.mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels; audioFormat.mFramesPerPacket = 1; audioFormat.mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample; audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame; audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket; audioFormat.mReserved = 0; status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &audioFormat, sizeof(audioFormat)); if(status){ TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status); return -5; } else { // configure if(tdav_audiounit_handle_configure(consumer->audioUnitHandle, tsk_true, TMEDIA_CONSUMER(consumer)->audio.ptime, &audioFormat)){ TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_CONSUMER(consumer)->audio.out.rate); return -4; } // set callback function AURenderCallbackStruct callback; callback.inputProc = __handle_output_buffer; callback.inputProcRefCon = consumer; status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); if(status){ TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); return -6; } } } // allocate the chunck buffer and create the ring consumer->ring.chunck.size = (TMEDIA_CONSUMER(consumer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000; consumer->ring.size = kRingPacketCount * consumer->ring.chunck.size; if(!(consumer->ring.chunck.buffer = tsk_realloc(consumer->ring.chunck.buffer, consumer->ring.chunck.size))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); return -7; } if(!consumer->ring.buffer){ consumer->ring.buffer = speex_buffer_init(consumer->ring.size); } else { int ret; if((ret = speex_buffer_resize(consumer->ring.buffer, consumer->ring.size)) < 0){ TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", consumer->ring.size, ret); return ret; } } if(!consumer->ring.buffer){ TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", consumer->ring.size); return -8; } if(!consumer->ring.mutex && !(consumer->ring.mutex = tsk_mutex_create_2(tsk_false))){ TSK_DEBUG_ERROR("Failed to create mutex"); return -9; } // set maximum frames per slice as buffer size //UInt32 numFrames = (UInt32)consumer->ring.chunck.size; //status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), // kAudioUnitProperty_MaximumFramesPerSlice, // kAudioUnitScope_Global, // 0, // &numFrames, // sizeof(numFrames)); //if(status){ // TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_MaximumFramesPerSlice, %u) failed with status=%d", (unsigned)numFrames, (int32_t)status); // return -6; //} TSK_DEBUG_INFO("AudioUnit consumer prepared"); return tdav_audiounit_handle_signal_consumer_prepared(consumer->audioUnitHandle); }
int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr) { #if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled"); return -1; #else tnet_dtls_socket_t *socket = handle; int ret = 0, len; void* out_data; if (!socket) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_safeobj_lock(socket); // update remote address even if handshaking is completed if (remote_addr) { socket->remote.addr = *remote_addr; } if (socket->handshake_completed) { TSK_DEBUG_INFO("Handshake completed"); ret = 0; goto bail; } if (!socket->handshake_started) { if ((ret = SSL_do_handshake(socket->ssl)) != 1) { switch ((ret = SSL_get_error(socket->ssl, ret))) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_NONE: break; default: TSK_DEBUG_ERROR("DTLS handshake failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_failed); ret = -2; goto bail; } } socket->handshake_started = (ret == SSL_ERROR_NONE); // TODO: reset for renegotiation } if ((len = (int)BIO_get_mem_data(socket->wbio, &out_data)) > 0 && out_data) { if (socket->handshake_storedata) { // e.g. when TURN is enabled we have to query handshaking data and sent it via the negotiated channel if ((int)socket->handshake_data.size < len) { if (!(socket->handshake_data.ptr = tsk_realloc(socket->handshake_data.ptr, len))) { socket->handshake_data.size = 0; socket->handshake_data.count = 0; ret = -5; goto bail; } socket->handshake_data.size = len; } socket->handshake_data.count = len; memcpy(socket->handshake_data.ptr, out_data, len); } else { int sentlen = 0; tnet_port_t port; tnet_ip_t ip; tsk_bool_t is_dgram = TNET_SOCKET_TYPE_IS_DGRAM(socket->wrapped_sock->type); const uint8_t *record_ptr, *records_ptr = out_data; tsk_size_t record_size; int records_len = len; tnet_get_sockip_n_port((const struct sockaddr *)&socket->remote.addr, &ip, &port); TSK_DEBUG_INFO("DTLS data handshake to send with len = %d, from(%.*s/%d) to(%.*s/%d)", len, (int)sizeof(socket->wrapped_sock->ip), socket->wrapped_sock->ip, socket->wrapped_sock->port, (int)sizeof(ip), ip, port); //!\ IP fragmentation issues must be avoided even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, &record_ptr, &record_size)) == 0) { if (is_dgram) { sentlen += tnet_sockfd_sendto(socket->wrapped_sock->fd, (const struct sockaddr *)&socket->remote.addr, record_ptr, record_size); } else { sentlen += tnet_socket_send_stream(socket->wrapped_sock, record_ptr, record_size); } records_len -= (int)record_size; records_ptr += record_size; } TSK_DEBUG_INFO("DTLS data handshake sent len = %d", sentlen); } } BIO_reset(socket->rbio); BIO_reset(socket->wbio); if ((socket->handshake_completed = SSL_is_init_finished(socket->ssl))) { TSK_DEBUG_INFO("DTLS handshake completed"); #if HAVE_OPENSSL_DTLS_SRTP if (socket->use_srtp){ #if !defined(SRTP_MAX_KEY_LEN) # define cipher_key_length (128 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles # define cipher_salt_length (112 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles // "cipher_key_length" is also equal to srtp_profile_get_master_key_length(srtp_profile_aes128_cm_sha1_80) // "cipher_salt_length" is also srtp_profile_get_master_salt_length(srtp_profile_aes128_cm_sha1_80) # define SRTP_MAX_KEY_LEN (cipher_key_length + cipher_salt_length) #endif /* SRTP_MAX_KEY_LEN */ #define EXTRACTOR_dtls_srtp_text "EXTRACTOR-dtls_srtp" #define EXTRACTOR_dtls_srtp_text_len 19 uint8_t keying_material[SRTP_MAX_KEY_LEN << 1]; static const tsk_size_t keying_material_size = sizeof(keying_material); /*if(socket->use_srtp)*/{ SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(socket->ssl); if (!p) { TSK_DEBUG_ERROR("SSL_get_selected_srtp_profile() returned null [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } // alert user _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_profile_selected, p->name, tsk_strlen(p->name)); memset(keying_material, 0, sizeof(keying_material)); // rfc5764 - 4.2. Key Derivation ret = SSL_export_keying_material(socket->ssl, keying_material, sizeof(keying_material), EXTRACTOR_dtls_srtp_text, EXTRACTOR_dtls_srtp_text_len, tsk_null, 0, 0); if (ret != 1) { // alert listener _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_error); TSK_DEBUG_ERROR("SSL_export_keying_material() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); ret = -2; goto bail; } } // alert listener _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_data, keying_material, keying_material_size); } #endif /* HAVE_OPENSSL_DTLS_SRTP */ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_succeed); } ret = 0; // clear "ret", error will directly jump to "bail:" bail: tsk_safeobj_unlock(socket); return ret; #endif }
tsk_size_t tdav_codec_mp4ves_decode(tmedia_codec_t* _self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { tdav_codec_mp4ves_t* self = (tdav_codec_mp4ves_t*)_self; const trtp_rtp_header_t* rtp_hdr = proto_hdr; tsk_size_t xsize, retsize = 0; int got_picture_ptr; int ret; if(!self || !in_data || !in_size || !out_data || !self->decoder.context){ TSK_DEBUG_ERROR("Invalid parameter"); return 0; } // get expected size xsize = avpicture_get_size(self->decoder.context->pix_fmt, self->decoder.context->width, self->decoder.context->height); /* Packet lost? */ if(self->decoder.last_seq != (rtp_hdr->seq_num - 1) && self->decoder.last_seq){ if(self->decoder.last_seq == rtp_hdr->seq_num){ // Could happen on some stupid emulators TSK_DEBUG_INFO("Packet duplicated, seq_num=%d", rtp_hdr->seq_num); return 0; } TSK_DEBUG_INFO("Packet lost, seq_num=%d", rtp_hdr->seq_num); } self->decoder.last_seq = rtp_hdr->seq_num; if((self->decoder.accumulator_pos + in_size) <= xsize){ memcpy(&((uint8_t*)self->decoder.accumulator)[self->decoder.accumulator_pos], in_data, in_size); self->decoder.accumulator_pos += in_size; } else{ TSK_DEBUG_WARN("Buffer overflow"); self->decoder.accumulator_pos = 0; return 0; } if(rtp_hdr->marker){ AVPacket packet; /* allocate destination buffer */ if(*out_max_size <xsize){ if(!(*out_data = tsk_realloc(*out_data, xsize))){ TSK_DEBUG_ERROR("Failed to allocate new buffer"); self->decoder.accumulator_pos = 0; *out_max_size = 0; return 0; } *out_max_size = xsize; } av_init_packet(&packet); packet.size = (int)self->decoder.accumulator_pos; packet.data = self->decoder.accumulator; ret = avcodec_decode_video2(self->decoder.context, self->decoder.picture, &got_picture_ptr, &packet); if(ret < 0){ TSK_DEBUG_WARN("Failed to decode the buffer with error code = %d", ret); if(TMEDIA_CODEC_VIDEO(self)->in.callback){ TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_error; TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); } } else if(got_picture_ptr){ retsize = xsize; TMEDIA_CODEC_VIDEO(self)->in.width = self->decoder.context->width; TMEDIA_CODEC_VIDEO(self)->in.height = self->decoder.context->height; /* copy picture into a linear buffer */ avpicture_layout((AVPicture *)self->decoder.picture, self->decoder.context->pix_fmt, (int)self->decoder.context->width, (int)self->decoder.context->height, *out_data, (int)retsize); } /* in all cases: reset accumulator */ self->decoder.accumulator_pos = 0; } return retsize; }
static tsk_size_t tdav_codec_h264_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; const trtp_rtp_header_t* rtp_hdr = (const trtp_rtp_header_t*)proto_hdr; const uint8_t* pay_ptr = tsk_null; tsk_size_t pay_size = 0; int ret; tsk_bool_t sps_or_pps, append_scp, end_of_unit; tsk_size_t retsize = 0, size_to_copy = 0; static const tsk_size_t xmax_size = (3840 * 2160 * 3) >> 3; // >>3 instead of >>1 (not an error) static tsk_size_t start_code_prefix_size = sizeof(H264_START_CODE_PREFIX); #if HAVE_FFMPEG int got_picture_ptr = 0; #endif if(!h264 || !in_data || !in_size || !out_data #if HAVE_FFMPEG || !h264->decoder.context #endif ) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } //TSK_DEBUG_INFO("SeqNo=%hu", rtp_hdr->seq_num); /* Packet lost? */ if((h264->decoder.last_seq + 1) != rtp_hdr->seq_num && h264->decoder.last_seq){ TSK_DEBUG_INFO("[H.264] Packet loss, seq_num=%d", (h264->decoder.last_seq + 1)); } h264->decoder.last_seq = rtp_hdr->seq_num; /* 5.3. NAL Unit Octet Usage +---------------+ |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |F|NRI| Type | +---------------+ */ if(*((uint8_t*)in_data) & 0x80){ TSK_DEBUG_WARN("F=1"); /* reset accumulator */ h264->decoder.accumulator_pos = 0; return 0; } /* get payload */ if((ret = tdav_codec_h264_get_pay(in_data, in_size, (const void**)&pay_ptr, &pay_size, &append_scp, &end_of_unit)) || !pay_ptr || !pay_size){ TSK_DEBUG_ERROR("Depayloader failed to get H.264 content"); return 0; } //append_scp = tsk_true; size_to_copy = pay_size + (append_scp ? start_code_prefix_size : 0); // whether it's SPS or PPS (append_scp is false for subsequent FUA chuncks) sps_or_pps = append_scp && pay_ptr && ((pay_ptr[0] & 0x1F) == 7 || (pay_ptr[0] & 0x1F) == 8); // start-accumulator if(!h264->decoder.accumulator){ if(size_to_copy > xmax_size){ TSK_DEBUG_ERROR("%u too big to contain valid encoded data. xmax_size=%u", size_to_copy, xmax_size); return 0; } if(!(h264->decoder.accumulator = tsk_calloc(size_to_copy, sizeof(uint8_t)))){ TSK_DEBUG_ERROR("Failed to allocated new buffer"); return 0; } h264->decoder.accumulator_size = size_to_copy; } if((h264->decoder.accumulator_pos + size_to_copy) >= xmax_size){ TSK_DEBUG_ERROR("BufferOverflow"); h264->decoder.accumulator_pos = 0; return 0; } if((h264->decoder.accumulator_pos + size_to_copy) > h264->decoder.accumulator_size){ if(!(h264->decoder.accumulator = tsk_realloc(h264->decoder.accumulator, (h264->decoder.accumulator_pos + size_to_copy)))){ TSK_DEBUG_ERROR("Failed to reallocated new buffer"); h264->decoder.accumulator_pos = 0; h264->decoder.accumulator_size = 0; return 0; } h264->decoder.accumulator_size = (h264->decoder.accumulator_pos + size_to_copy); } if(append_scp){ memcpy(&((uint8_t*)h264->decoder.accumulator)[h264->decoder.accumulator_pos], H264_START_CODE_PREFIX, start_code_prefix_size); h264->decoder.accumulator_pos += start_code_prefix_size; } memcpy(&((uint8_t*)h264->decoder.accumulator)[h264->decoder.accumulator_pos], pay_ptr, pay_size); h264->decoder.accumulator_pos += pay_size; // end-accumulator if(sps_or_pps){ // http://libav-users.943685.n4.nabble.com/Decode-H264-streams-how-to-fill-AVCodecContext-from-SPS-PPS-td2484472.html // SPS and PPS should be bundled with IDR TSK_DEBUG_INFO("Receiving SPS or PPS ...to be tied to an IDR"); } else if(rtp_hdr->marker){ if(h264->decoder.passthrough){ if(*out_max_size < h264->decoder.accumulator_pos){ if((*out_data = tsk_realloc(*out_data, h264->decoder.accumulator_pos))){ *out_max_size = h264->decoder.accumulator_pos; } else{ *out_max_size = 0; return 0; } } memcpy(*out_data, h264->decoder.accumulator, h264->decoder.accumulator_pos); retsize = h264->decoder.accumulator_pos; } else { // !h264->decoder.passthrough #if HAVE_FFMPEG AVPacket packet; /* decode the picture */ av_init_packet(&packet); packet.dts = packet.pts = AV_NOPTS_VALUE; packet.size = (int)h264->decoder.accumulator_pos; packet.data = h264->decoder.accumulator; ret = avcodec_decode_video2(h264->decoder.context, h264->decoder.picture, &got_picture_ptr, &packet); if(ret <0){ TSK_DEBUG_INFO("Failed to decode the buffer with error code =%d, size=%u, append=%s", ret, h264->decoder.accumulator_pos, append_scp ? "yes" : "no"); if(TMEDIA_CODEC_VIDEO(self)->in.callback){ TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_error; TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); } } else if(got_picture_ptr){ tsk_size_t xsize; /* IDR ? */ if(((pay_ptr[0] & 0x1F) == 0x05) && TMEDIA_CODEC_VIDEO(self)->in.callback){ TSK_DEBUG_INFO("Decoded H.264 IDR"); TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_idr; TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); } /* fill out */ xsize = avpicture_get_size(h264->decoder.context->pix_fmt, h264->decoder.context->width, h264->decoder.context->height); if(*out_max_size<xsize){ if((*out_data = tsk_realloc(*out_data, (xsize + FF_INPUT_BUFFER_PADDING_SIZE)))){ *out_max_size = xsize; } else{ *out_max_size = 0; return 0; } } retsize = xsize; TMEDIA_CODEC_VIDEO(h264)->in.width = h264->decoder.context->width; TMEDIA_CODEC_VIDEO(h264)->in.height = h264->decoder.context->height; avpicture_layout((AVPicture *)h264->decoder.picture, h264->decoder.context->pix_fmt, (int)h264->decoder.context->width, (int)h264->decoder.context->height, *out_data, (int)retsize); } #endif /* HAVE_FFMPEG */ } // else(h264->decoder.passthrough) h264->decoder.accumulator_pos = 0; } // else if(rtp_hdr->marker) return retsize; }