📄 test_repair.c
字号:
#include "config_win32.h"#include "config_unix.h"#include "audio_types.h"#include "codec_types.h"#include "codec_state.h"#include "codec.h"#include "repair_types.h"#include "repair.h"#include "sndfile_types.h"#include "sndfile.h"#include "util.h"#include <stdlib.h>#include <stdio.h>/* * test_repair: this test takes an audio file, codes it, and simulates * loss on the coded audio, and writes a file of what would be decoded * when error concealment is applied. *//* drop code - want to have additive drop so if we run test with 5% * and 10% and the same seed, the loss pattern of the 10% is the 5% plus * another 5%. */#define DROP_ARRAY_SIZE 192000#define RANDOM_END 0x7fffffffstatic unsigned char drop_priv[DROP_ARRAY_SIZE];static int units_per_packet = 1;static void init_drop(int seed, double d){ int ndrop = (int)(d * sizeof(drop_priv)); int dropped; unsigned int rand_ceil = RANDOM_END - (RANDOM_END % DROP_ARRAY_SIZE); unsigned int r; memset(drop_priv, 0, sizeof(drop_priv)); srand48(seed); for (dropped = 0; dropped < ndrop; dropped ++) { /* Keep picking numbers until we get one in range and * that has not already been picked. */ while( (r = (mrand48() & 0x7fffffff)) > rand_ceil && drop_priv[r % DROP_ARRAY_SIZE]); drop_priv[r % DROP_ARRAY_SIZE] = 1; } printf("# dropping %d of %d frames\n", ndrop, DROP_ARRAY_SIZE);}static intdo_drop(){ static long int idx; int d; d = drop_priv[idx / units_per_packet]; idx = (idx + 1) % DROP_ARRAY_SIZE; return d;}#define READ_BUF_SIZE 2560static intread_and_encode(coded_unit *out, codec_state *encoder, struct s_sndfile *sf_in){ const codec_format_t *cf; coded_unit dummy; sample *buf; uint16_t req_samples, act_samples; req_samples = codec_get_samples_per_frame(encoder->id); buf = (sample*)block_alloc(sizeof(sample) * req_samples); act_samples = (uint16_t)snd_read_audio(&sf_in, buf, req_samples); if (req_samples != act_samples) { memset(buf + act_samples, 0, sizeof(short) * (req_samples - act_samples)); } cf = codec_get_format(encoder->id); assert(cf != NULL); dummy.id = codec_get_native_coding((uint16_t)cf->format.sample_rate, (uint16_t)cf->format.channels); dummy.state = NULL; dummy.state_len = 0; dummy.data = (u_char*)buf; dummy.data_len = req_samples * sizeof(short); assert(out != NULL); if (codec_encode(encoder, &dummy, out) == FALSE) { abort(); } block_free(dummy.data, dummy.data_len); return (sf_in != NULL);}static voiddecode_and_write(struct s_sndfile *sf_out, struct s_codec_state_store *decoder_states, media_data *md){ codec_state *decoder; coded_unit *cu; int i; assert(md->nrep > 0); for(i = 0; i < md->nrep; i++) { if (codec_is_native_coding(md->rep[i]->id)) { break; } } if (i == md->nrep) { /* no decoded audio available for frame */ cu = (coded_unit*)block_alloc(sizeof(coded_unit)); assert(cu != NULL); memset(cu, 0, sizeof(coded_unit)); decoder = codec_state_store_get(decoder_states, md->rep[0]->id); codec_decode(decoder, md->rep[0], cu); assert(md->rep[md->nrep] == NULL); md->rep[md->nrep] = cu; md->nrep++; } assert(codec_is_native_coding(md->rep[md->nrep - 1]->id)); assert(sf_out != NULL); snd_write_audio(&sf_out, (sample*)md->rep[md->nrep - 1]->data, md->rep[md->nrep - 1]->data_len / sizeof(sample)); } static voidtest_repair(struct s_sndfile *sf_out, codec_id_t cid, repair_id_t repair_type, struct s_sndfile *sf_in){ codec_state *encoder; struct s_codec_state_store *decoder_states; media_data *md_prev, *md_cur; coded_unit *cu; int32_t consec_lost = 0, total_lost, total_done; const codec_format_t *cf; uint16_t i; repair_id_t repair_none; for (i = 0; i < repair_get_count(); i++) { const repair_details_t *rd; rd = repair_get_details(i); if (strcasecmp(rd->name, "none") == 0) { repair_none = rd->id; break; } } codec_encoder_create(cid, &encoder); codec_state_store_create(&decoder_states, DECODER); cf = codec_get_format(cid); /* Read and write one unit to kick off with */ media_data_create(&md_cur, 1); read_and_encode(md_cur->rep[0], encoder, sf_in); decode_and_write(sf_out, decoder_states, md_cur); /* Initialize next reading cycle */ md_prev = md_cur; md_cur = NULL; media_data_create(&md_cur, 1); total_lost = total_done = 0; while(read_and_encode(md_cur->rep[0], encoder, sf_in)) { total_done++; if (do_drop()) { total_lost++; media_data_destroy(&md_cur, sizeof(media_data)); media_data_create(&md_cur, 0); cu = (coded_unit*)block_alloc(sizeof(coded_unit)); assert(cu != NULL); memset(cu, 0, sizeof(coded_unit)); /* Loss happens - invoke repair */ if (repair_type != repair_none) { cu->id = cid; repair(repair_type, consec_lost, decoder_states, md_prev, cu); } else { /* Create a silent unit */ cu->id = codec_get_native_coding((uint16_t)cf->format.sample_rate, (uint16_t)cf->format.channels); cu->state = NULL; cu->state_len = 0; cu->data = (u_char*)block_alloc(cf->format.bytes_per_block); cu->data_len = cf->format.bytes_per_block; memset(cu->data, 0, cu->data_len); } /* Add repaired audio to frame */ md_cur->rep[md_cur->nrep] = cu; md_cur->nrep++; consec_lost++; } else { consec_lost = 0; } decode_and_write(sf_out, decoder_states, md_cur); media_data_destroy(&md_prev, sizeof(media_data)); md_prev = md_cur; md_cur = NULL; media_data_create(&md_cur, 1); } printf("# Dropped %d frames out of %d (%f loss %%)\n", total_lost, total_done, 100.0 * total_lost / (double)total_done); media_data_destroy(&md_cur, sizeof(media_data)); media_data_destroy(&md_prev, sizeof(media_data)); codec_encoder_destroy(&encoder); codec_state_store_destroy(&decoder_states);}static voidusage(void){ fprintf(stderr, "test_repair [options] -c <codec> -r <repair> -d <rate> <src_file> <dst_file>where options are:\t-codecs to list available codecs\t-repairs to list available repair schemes\t-n to disable codec specific repair (default csra permitted)\t-s <seed> to set seed of rng (default 0)\t-u <units> set audio frames per packet (default 1 == 20ms)\n"); exit(-1);} static voidlist_repairs(void){ /* Repair interface is not consistent with other interfaces. * Does not have get_format get_details type fn, just get_name * (grumble, grumble, time, grumble) */ const repair_details_t *rd; uint16_t i, cnt; cnt = repair_get_count(); for(i = 0; i < cnt; i++) { rd = repair_get_details(i); printf("%s\n", rd->name); } return;}static intfile_and_codec_compatible(const sndfile_fmt_t *sff, codec_id_t cid){ const codec_format_t *cf; cf = codec_get_format(cid); if (cf == NULL) { return FALSE; } if (sff->sample_rate == (uint32_t)cf->format.sample_rate && sff->channels == (uint32_t)cf->format.channels) { return TRUE; } return FALSE;}static voidlist_codecs(void){ uint32_t i, cnt; codec_id_t cid; const codec_format_t *cf; cnt = codec_get_number_of_codecs(); for(i = 0; i < cnt; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); printf("%s\n", cf->long_name); } return;}static voidresolve_repair(char *reqname, repair_id_t *rid, const char **actualname){ uint16_t i,n; const repair_details_t *rd; n = repair_get_count(); for (i = 0; i < n; i++) { rd = repair_get_details(i); if (strcasecmp(rd->name, reqname) == 0) { *rid = rd->id; *actualname = rd->name; return; } } fprintf(stderr, "Repair type %s not recognized\n", reqname); exit(-1);}int main(int argc, char *argv[]){ const char *codec_name, *repair_name; codec_id_t cid; repair_id_t rid; struct s_sndfile *sf_in = NULL, *sf_out = NULL; sndfile_fmt_t sff; double drop = 0.0; int ac, did_query = FALSE; int csra = TRUE; /* codec specific repair allowed */ long seed = 100; codec_init(); ac = 1; while(ac < argc && argv[ac][0] == '-') { if (strlen(argv[ac]) > 2) { /* should be -codecs or -repairs */ switch(argv[ac][1]) { case 'c': list_codecs(); break; case 'r': list_repairs(); break; default: usage(); } did_query = TRUE; } else { if (argc - ac < 1) { usage(); } switch(argv[ac][1]) { case 's': seed = atoi(argv[++ac]); break; case 'd': drop = strtod(argv[++ac], NULL); break; case 'c': cid = codec_get_by_name(argv[++ac]); codec_name = argv[ac]; break; case 'n': csra = FALSE; break; case 'r': resolve_repair(argv[++ac], &rid, &repair_name); break; case 'u': units_per_packet = atoi(argv[++ac]); break; default: usage(); } } ac++; } if (did_query == TRUE) { /* Not sensible to be running query and executing test */ exit(-1); } if (argc - ac != 2) { usage(); } if (snd_read_open(&sf_in, argv[ac], NULL) == FALSE) { fprintf(stderr, "Could not open %s\n", argv[ac]); exit(-1); } ac++; if (snd_get_format(sf_in, &sff) == FALSE) { fprintf(stderr, "Failed to get format of %s\n", argv[ac]); exit(-1); } if (snd_write_open(&sf_out, argv[ac], "au", &sff) == FALSE) { fprintf(stderr, "Could not open %s\n", argv[ac]); exit(-1); } if (file_and_codec_compatible(&sff, cid) == FALSE) { fprintf(stderr, "Codec and file type are not compatible\n"); exit(-1); } printf("# Parameters#\tseed: %ld#\tdrop: %.2f#\tcodec: %s#\tunits per packet: %d#\trepair: %s#\tcodec specific repair (when available): %d#\tsource file: %s#\tdestination file %s\n",seed, drop, codec_name, units_per_packet, repair_name, csra, argv[argc - 2], argv[argc - 1]); repair_set_codec_specific_allowed(csra); init_drop(seed, drop); test_repair(sf_out, cid, rid, sf_in); /* snd_read_close(&sf_in) not needed because files gets closed * at eof automatically. */ snd_write_close(&sf_out); codec_exit(); xmemdmp(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -