Related
This is the Original code:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#else
#include <sys/select.h>
#endif
#include <sphinxbase/err.h>
#include <sphinxbase/ad.h>
#include "pocketsphinx.h"
static const arg_t cont_args_def[] = {
POCKETSPHINX_OPTIONS,
/* Argument file. */
{"-argfile",
ARG_STRING,
NULL,
"Argument file giving extra arguments."},
{"-adcdev",
ARG_STRING,
NULL,
"Name of audio device to use for input."},
{"-infile",
ARG_STRING,
NULL,
"Audio file to transcribe."},
{"-inmic",
ARG_BOOLEAN,
"no",
"Transcribe audio from microphone."},
{"-time",
ARG_BOOLEAN,
"no",
"Print word times in file transcription."},
CMDLN_EMPTY_OPTION
};
static ps_decoder_t *ps;
static cmd_ln_t *config;
static FILE *rawfd;
static void
print_word_times()
{
int frame_rate = cmd_ln_int32_r(config, "-frate");
ps_seg_t *iter = ps_seg_iter(ps);
while (iter != NULL) {
int32 sf, ef, pprob;
float conf;
ps_seg_frames(iter, &sf, &ef);
pprob = ps_seg_prob(iter, NULL, NULL, NULL);
conf = logmath_exp(ps_get_logmath(ps), pprob);
printf("%s %.3f %.3f %f\n", ps_seg_word(iter), ((float)sf / frame_rate),
((float) ef / frame_rate), conf);
iter = ps_seg_next(iter);
}
}
static int
check_wav_header(char *header, int expected_sr)
{
int sr;
if (header[34] != 0x10) {
E_ERROR("Input audio file has [%d] bits per sample instead of 16\n", header[34]);
return 0;
}
if (header[20] != 0x1) {
E_ERROR("Input audio file has compression [%d] and not required PCM\n", header[20]);
return 0;
}
if (header[22] != 0x1) {
E_ERROR("Input audio file has [%d] channels, expected single channel mono\n", header[22]);
return 0;
}
sr = ((header[24] & 0xFF) | ((header[25] & 0xFF) << 8) | ((header[26] & 0xFF) << 16) | ((header[27] & 0xFF) << 24));
if (sr != expected_sr) {
E_ERROR("Input audio file has sample rate [%d], but decoder expects [%d]\n", sr, expected_sr);
return 0;
}
return 1;
}
/*
* Continuous recognition from a file
*/
static void
recognize_from_file()
{
int16 adbuf[2048];
const char *fname;
const char *hyp;
int32 k;
uint8 utt_started, in_speech;
int32 print_times = cmd_ln_boolean_r(config, "-time");
fname = cmd_ln_str_r(config, "-infile");
if ((rawfd = fopen(fname, "rb")) == NULL) {
E_FATAL_SYSTEM("Failed to open file '%s' for reading",
fname);
}
if (strlen(fname) > 4 && strcmp(fname + strlen(fname) - 4, ".wav") == 0) {
char waveheader[44];
fread(waveheader, 1, 44, rawfd);
if (!check_wav_header(waveheader, (int)cmd_ln_float32_r(config, "-samprate")))
E_FATAL("Failed to process file '%s' due to format mismatch.\n", fname);
}
if (strlen(fname) > 4 && strcmp(fname + strlen(fname) - 4, ".mp3") == 0) {
E_FATAL("Can not decode mp3 files, convert input file to WAV 16kHz 16-bit mono before decoding.\n");
}
ps_start_utt(ps);
utt_started = FALSE;
while ((k = fread(adbuf, sizeof(int16), 2048, rawfd)) > 0) {
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
in_speech = ps_get_in_speech(ps);
if (in_speech && !utt_started) {
utt_started = TRUE;
}
if (!in_speech && utt_started) {
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL);
if (hyp != NULL)
printf("%s\n", hyp);
if (print_times)
print_word_times();
fflush(stdout);
ps_start_utt(ps);
utt_started = FALSE;
}
}
ps_end_utt(ps);
if (utt_started) {
hyp = ps_get_hyp(ps, NULL);
if (hyp != NULL) {
printf("%s\n", hyp);
if (print_times) {
print_word_times();
}
}
}
fclose(rawfd);
}
/* Sleep for specified msec */
static void
sleep_msec(int32 ms)
{
#if (defined(_WIN32) && !defined(GNUWINCE)) || defined(_WIN32_WCE)
Sleep(ms);
#else
/* ------------------- Unix ------------------ */
struct timeval tmo;
tmo.tv_sec = 0;
tmo.tv_usec = ms * 1000;
select(0, NULL, NULL, NULL, &tmo);
#endif
}
/*
* Main utterance processing loop:
* for (;;) {
* start utterance and wait for speech to process
* decoding till end-of-utterance silence will be detected
* print utterance result;
* }
*/
static void
recognize_from_microphone()
{
ad_rec_t *ad;
int16 adbuf[2048];
uint8 utt_started, in_speech;
int32 k;
char const *hyp;
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int) cmd_ln_float32_r(config,
"-samprate"))) == NULL)
E_FATAL("Failed to open audio device\n");
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
if (ps_start_utt(ps) < 0)
E_FATAL("Failed to start utterance\n");
utt_started = FALSE;
E_INFO("Ready....\n");
for (;;) {
if ((k = ad_read(ad, adbuf, 2048)) < 0)
E_FATAL("Failed to read audio\n");
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
in_speech = ps_get_in_speech(ps);
if (in_speech && !utt_started) {
utt_started = TRUE;
E_INFO("Listening...\n");
}
if (!in_speech && utt_started) {
/* speech -> silence transition, time to start new utterance */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL );
if (hyp != NULL) {
printf("%s\n", hyp);
fflush(stdout);
}
if (ps_start_utt(ps) < 0)
E_FATAL("Failed to start utterance\n");
utt_started = FALSE;
E_INFO("Ready....\n");
}
sleep_msec(100);
}
ad_close(ad);
}
int
main(int argc, char *argv[])
{
char const *cfg;
config = cmd_ln_parse_r(NULL, cont_args_def, argc, argv, TRUE);
/* Handle argument file as -argfile. */
if (config && (cfg = cmd_ln_str_r(config, "-argfile")) != NULL) {
config = cmd_ln_parse_file_r(config, cont_args_def, cfg, FALSE);
}
if (config == NULL || (cmd_ln_str_r(config, "-infile") == NULL && cmd_ln_boolean_r(config, "-inmic") == FALSE)) {
E_INFO("Specify '-infile <file.wav>' to recognize from file or '-inmic yes' to recognize from microphone.\n");
cmd_ln_free_r(config);
return 1;
}
ps_default_search_args(config);
ps = ps_init(config);
if (ps == NULL) {
cmd_ln_free_r(config);
return 1;
}
E_INFO("%s COMPILED ON: %s, AT: %s\n\n", argv[0], __DATE__, __TIME__);
if (cmd_ln_str_r(config, "-infile") != NULL) {
recognize_from_file();
} else if (cmd_ln_boolean_r(config, "-inmic")) {
recognize_from_microphone();
}
ps_free(ps);
cmd_ln_free_r(config);
return 0;
}
#if defined(_WIN32_WCE)
#pragma comment(linker,"/entry:mainWCRTStartup")
#include <windows.h>
//Windows Mobile has the Unicode main only
int
wmain(int32 argc, wchar_t * wargv[])
{
char **argv;
size_t wlen;
size_t len;
int i;
argv = malloc(argc * sizeof(char *));
for (i = 0; i < argc; i++) {
wlen = lstrlenW(wargv[i]);
len = wcstombs(NULL, wargv[i], wlen);
argv[i] = malloc(len + 1);
wcstombs(argv[i], wargv[i], wlen);
}
//assuming ASCII parameters
return main(argc, argv);
}
#endif
I can compile it by this command:
g++ -o output continuous.cpp -DMODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\" `pkg-config --cflags --libs pocketsphinx sphinxbase`
And run it by this command : output -inmic yes .
But I like to convert the code as it has no need to get inmic yes and it automatically starts the program from microphone. But I got segmentation fault(core dumped) error when I changed these parts:
static const arg_t cont_args_def= {"-inmic",
ARG_BOOLEAN,
"no",
"Transcribe audio from microphone."};
int main(int argc, char *argv[])
{
config = cmd_ln_parse_r(NULL, cont_args_def, argc, argv, TRUE);
if (cmd_ln_boolean_r(config, "-inmic")) {
recognize_from_microphone();
}
// recognize_from_microphone();
ps_free(ps);
cmd_ln_free_r(config);
return 0;
}
I searched a lot and red the documentation but couldn't understand what's the problem?
Change the last argument passed to cmd_ln_parse_r from TRUE to FALSE.
It has something to do with strict checking.
I figured this out by reading the source code for cmd_ln.c in the sphinxbase code.
I also changed the boolean value for -inmic in cont_args_def from "no" to "yes".
My linux application can use libusb to perform many IO operations to/from the device. However, if I close and then re-open access to the device, all read operations will timeout. I'm assuming that my close code is not complete but I can't find my bug.
The example program has these functions:
deviceCount( ) which returns the number of devices matching my VID/PID
deviceOpen( ) to open a connection to my device
deviceClose( ) to close the connection to my device and "clean-up"
deviceWrite( ) to write a specific number of bytes to my device
deviceRead( ) to read a specific number of bytes from my device
deviceReadRegisters( ) a function specific to my device that does a write followed by a read
runTest( ) a function to call all of the above in a reasonable sequence
main( ) the main function which tries to call runTest( ) multiple times.
Note that after running the program and getting the timeout error, I need to power-cycle my device to recover. Re-running my test program without power-cycling is not sufficient. It will then fail on the first call to runTest( ).
In the current implementation, I only call libusb_init( ) and libusb_exit( ) once. I've also tried calling these function each time through the runTest( ) function. This didn't make any difference.
I'm guessing that I'm doing something wrong in my deviceClose( ) function. Any insights would be greatly appreciated.
Thanks in advance! - Jeff
####### Example output
main() attempting to runTest(), i: 0
runTest() Starting!
runTest() Success calling libusb_init()
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceWrite() Success writing 2 bytes
deviceRead() Success reading 146 bytes
deviceReadRegisters() Success!
deviceClose() Sucess calling libusb_release_interface( ) handle: 0x88cd140
deviceClose() Sucess calling libusb_close( ) handle: 0x88cd140
deviceClose() Success calling libusb_free_device_list( ) devs: 0x88cd170
runTest() Success!
main() attempting to runTest(), i: 1 <== this is the second call to runTest( )
runTest() Starting!
runTest() Number of devices: 1
deviceOpen() Number of alternate settings: 1
deviceOpen() Interface number: 0 number of endpoints: 5
deviceOpen() Descriptor type: 5 EP Address: 0x02 2
deviceOpen() Found outPort! outPort: 2 index: 0
deviceOpen() Descriptor type: 5 EP Address: 0x84 132
deviceOpen() Descriptor type: 5 EP Address: 0x86 134
deviceOpen() Found inPort! inPort: 134 index: 2
deviceOpen() Descriptor type: 5 EP Address: 0x01 1
deviceOpen() Descriptor type: 5 EP Address: 0x81 129
deviceOpen() Found device! VID: 0x0957 PID: 0x5f18 outPort: 2 inPort: 134
deviceOpen() Success calling libusb_claim_interface( ) handle: 0x88cd140
deviceOpen() Successful open! id: 0 handle: 0x88cd140
deviceWrite() Success writing 2 bytes
deviceRead() Problem reading 146 bytes, read only 0 bytes, inPort: 134 timeout: 2000 LIBUSB_ERROR_TIMEOUT
####### Test Program
// Test program demonstrating timeout problem following libusb_close()
//
// g++ -o libUsbTest libUsbTest.cpp -I /usr/local/include/libusb-1.0 -L /usr/local/lib -l usb-1.0
//
// sudo ./libUsbTest
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libusb.h>
// for test purposes, using global variable
libusb_device **devs = NULL;
libusb_device_handle *handle = NULL; // non-null when device is open
libusb_context *usbContext = NULL;
unsigned short outPort = 0;
unsigned short inPort = 0;
#define VID 0x957
#define PID 0x5f18
#define OUTPUT_ENDPOINT 2
#define INPUT_ENDPOINT 6
// Returns the number of devices matching our VID / PID
// A negative return value indicates a failure
int deviceCount( ) {
int count = 0;
if (devs)
{
// Note this automatically dereferrences each device
libusb_free_device_list(devs, 1);
devs = NULL;
}
ssize_t cnt;
cnt = libusb_get_device_list(usbContext, &devs);
if (cnt < 0 || devs == 0)
{
fprintf(stderr,"deviceCount() Failed libusb_get_device_list()!\n");
return -1;
}
// Walk through the device list and count those that match our VID / PID
libusb_device *dev = NULL;
count = 0;
int i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "deviceCount() Failed libusb_get_device_descriptor()!\n");
return -1;
}
if (desc.idVendor == VID && desc.idProduct == PID)
{
count++;
}
}
return count;
}
// Open the USB device. Only one device can be open at a time because of the above global variables
// Returns negative number for errors
int deviceOpen( int id) {
if (!usbContext) {
fprintf(stderr,"deviceOpen() Can't open! Null usbContext!\n");
return -1;
}
if (handle) {
fprintf(stderr,"deviceOpen() Device already open!\n");
return 0;
}
if (devs == 0) {
fprintf(stderr,"deviceOpen() Can't open! Null devs!\n");
return -1;
}
// Walk through the same device list and stop when we get to the desired sensor VID / PID
libusb_device *dev = NULL;
int count = 0;
bool keepGoing = true;
int i = 0;
while ((dev = devs[i++]) != NULL && keepGoing) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "deviceOpen() Failed libusb_get_device_descriptor()!\n");
return -1;
}
if (desc.idVendor == VID && desc.idProduct == PID)
{
if (count == id) {
// Match!
keepGoing = false;
// Get the out and input ports
libusb_config_descriptor *config;
libusb_get_config_descriptor( dev, 0, &config);
const libusb_interface *inter;
const libusb_interface_descriptor *interdesc;
const libusb_endpoint_descriptor *epdesc;
for (int i=0; i<(int)config->bNumInterfaces; i++)
{
inter = &config->interface[i];
fprintf(stderr,"deviceOpen() Number of alternate settings: %d\n", inter->num_altsetting);
for (int j=0; j<inter->num_altsetting; j++)
{
interdesc = &inter->altsetting[j];
fprintf(stderr, "deviceOpen() Interface number: %d number of endpoints: %d\n",
interdesc->bInterfaceNumber, interdesc->bNumEndpoints);
for (int k=0; k<interdesc->bNumEndpoints; k++)
{
epdesc = &interdesc->endpoint[k];
fprintf(stderr, "deviceOpen() Descriptor type: %d EP Address: 0x%2.2x %d\n",
epdesc->bDescriptorType, epdesc->bEndpointAddress, epdesc->bEndpointAddress);
if (epdesc->bDescriptorType == LIBUSB_DT_ENDPOINT)
{
// Found an endpoint
uint8_t address = epdesc->bEndpointAddress & 0xf;
bool input = (epdesc->bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN;
if ( address == OUTPUT_ENDPOINT && input == false)
{
outPort = epdesc->bEndpointAddress;
fprintf(stderr, "deviceOpen() Found outPort! outPort: %d index: %d\n", outPort, k);
}
if ( address == INPUT_ENDPOINT && input == true)
{
inPort = epdesc->bEndpointAddress;
fprintf(stderr, "deviceOpen() Found inPort! inPort: %d index: %d\n", inPort, k);
}
}
} // endpoints}
} // num_altsetting
} // interfaces
libusb_free_config_descriptor( config);
// Open device
fprintf(stderr, "deviceOpen() Found device! VID: 0x%4.4x PID: 0x%4.4x outPort: %d inPort: %d\n", VID, PID, outPort, inPort);
libusb_error errCode;
errCode = (libusb_error) libusb_open( dev, &handle);
if (errCode)
{
fprintf(stderr, "deviceOpen() Failed in libusb_open(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
// Verify not in use by kernel
if (libusb_kernel_driver_active( handle, 0))
{
// FIXME: we could call libusb_detach_kernel_driver( ) here
fprintf(stderr, "deviceOpen() Failed! kernel owns device!\n");
return -1;
}
// Claim the interface.
errCode = (libusb_error) libusb_claim_interface( handle, 0);
if (errCode)
{
fprintf(stderr, "deviceOpen() Failed in libusb_claim_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
fprintf(stderr, "deviceOpen() Success calling libusb_claim_interface( ) handle: %p\n", handle);
} else {
count++;
}
} // desired VID / PID
} // Walk device list
fprintf(stderr, "deviceOpen() Successful open! id: %d handle: %p\n", id, handle);
return 0;
}
// Close the USB device
// Returns negative number for errors
int deviceClose() {
if (handle)
{
// Release the interface.
libusb_error errCode = (libusb_error) libusb_release_interface( handle, 0);
if (errCode)
{
fprintf(stderr, "deviceClose() Failed in libusb_release_interface(), err: %s (%d)\n", libusb_error_name( errCode), errCode);
return -1;
}
fprintf(stderr, "deviceClose() Sucess calling libusb_release_interface( ) handle: %p\n", handle);
libusb_close( handle);
fprintf(stderr, "deviceClose() Sucess calling libusb_close( ) handle: %p\n", handle);
handle = NULL;
}
if (devs)
{
// Note this automatically dereferrences each device
libusb_free_device_list(devs, 1);
fprintf(stderr, "deviceClose() Success calling libusb_free_device_list( ) devs: %p\n", devs);
devs = NULL;
}
outPort = 0;
inPort = 0;
return 0;
}
// Write to the device.
// Returns number of bytes written. Negative return value indicates an error
int deviceWrite( unsigned char *addr, int len){
if (!handle || !outPort) {
fprintf(stderr, "deviceWrite() No handle or outPort!\n");
return -1;
}
libusb_error errCode;
int transferred;
unsigned int timeout = 2000;
errCode = (libusb_error) libusb_bulk_transfer( handle, outPort, addr, len, &transferred, timeout);
if (errCode || transferred != len) {
fprintf(stderr, "deviceWrite() Problem writing %d bytes, wrote only %d bytes, outPort: %d timeout: %d %s\n",
len, transferred, outPort, timeout, libusb_error_name(errCode));
return -1;
}
fprintf(stderr, "deviceWrite() Success writing %ld bytes\n", transferred);
return transferred;
}
// Read from the device.
// Returns number of bytes read. Negative return value indicates an error
int deviceRead( unsigned char *addr, int len){
if (!handle || !outPort) {
fprintf(stderr, "deviceRead() No handle or outPort!\n");
return -1;
}
libusb_error errCode;
int transferred;
unsigned int timeout = 2000;
errCode = (libusb_error) libusb_bulk_transfer( handle, inPort, addr, len, &transferred, timeout);
if (errCode || (transferred != len)) {
fprintf(stderr, "deviceRead() Problem reading %ld bytes, read only %ld bytes, inPort: %d timeout: %d %s\n",
len, transferred, inPort, timeout, libusb_error_name(errCode));
return -1;
}
fprintf(stderr, "deviceRead() Success reading %ld bytes\n", transferred);
return transferred;
}
// Read the registers from the USB device
// Caution: this function is specific to my device!!!
// Returns negative number for errors
int deviceReadRegisters( ) {
// Write the command to the device so that it will return the registers
unsigned char wrBuf[2] = { 0x00, 0x10};
int rtn = deviceWrite( wrBuf, sizeof(wrBuf));
if (rtn < 0) return rtn;
// Read back 146 bytes
unsigned char rdBuf[146];
rtn = deviceRead( rdBuf, sizeof( rdBuf));
if (rtn < 0) return rtn;
// Just in case we add more logic later...
fprintf(stderr,"deviceReadRegisters() Success!\n");
return rtn;
}
// Execute the full test including initialization and cleanup
// Return negative number for error
int runTest( bool performLibUsbExit) {
int rtn;
fprintf(stderr,"runTest() Starting!\n");
// Initialize library
if (usbContext == NULL) {
int r = libusb_init( &usbContext);
if (r < 0)
{
fprintf(stderr,"runTest() failed in libusb_init()\n");
return -1;
}
fprintf(stderr,"runTest() Success calling libusb_init()\n");
}
// Make sure we have a device
int count = deviceCount();
if (count < 0) {
fprintf(stderr,"runTest() Error in deviceCount()\n");
return count;
}
if (count == 0) {
fprintf(stderr,"runTest() No devices found!\n");
return -1;
}
fprintf(stderr,"runTest() Number of devices: %d\n", count);
// Open the device
rtn = deviceOpen( 0);
if (rtn < 0) return rtn;
// Read the device registers a few times
for (int i=0; i<5; i++) {
rtn = deviceReadRegisters();
if (rtn < 0) return rtn;
}
// Close the device
rtn = deviceClose();
if (rtn < 0) return rtn;
// De-initialize the library
if (performLibUsbExit == true) {
libusb_exit(usbContext);
usbContext = NULL;
fprintf(stderr,"runTest() Success calling libusb_exit()\n");
}
fprintf(stderr,"runTest() Success!\n");
return 0;
}
int main( int argc, char *argv[]) {
int rtn;
// Run the test a few times
// The first test will pass. The second pass will timeout on the read.
int maxNum = 5;
for (int i=0; i<maxNum; i++) {
fprintf(stderr, "main() attempting to runTest(), i: %d\n", i);
// Only clean-up on the last call
rtn = runTest( i+1 == maxNum ? true : false);
if (rtn < 0) return rtn;
}
fprintf(stderr,"main() Success!\n");
return 0;
}
I want to resolve DNS SRV records using the iOS SDK.
I've already tried the high-level Bonjour APIs Apple is providing, but they're not what I need. Now I'm using DNS SD.
void *processQueryForSRVRecord(void *record) {
DNSServiceRef sdRef;
int context;
printf("Setting up query for record: %s\n", record);
DNSServiceQueryRecord(&sdRef, 0, 0, record, kDNSServiceType_SRV, kDNSServiceClass_IN, callback, &context);
printf("Processing query for record: %s\n", record);
DNSServiceProcessResult(sdRef);
printf("Deallocating query for record: %s\n", record);
DNSServiceRefDeallocate(sdRef);
return NULL;
}
This works as long as it gets only correct SRV records (for example: _xmpp-server._tcp.gmail.com), but when the record is typed wrong, DNSServiceProcessResult(sdRef) goes into an infinite loop.
Is there a way to stop DNSServiceProcessResult or must I cancel the thread calling it?
Use good old select(). This is what I have at the moment:
- (void)updateDnsRecords
{
if (self.dnsUpdatePending == YES)
{
return;
}
else
{
self.dnsUpdatePending = YES;
}
NSLog(#"DNS update");
DNSServiceRef sdRef;
DNSServiceErrorType err;
const char* host = [self.dnsHost UTF8String];
if (host != NULL)
{
NSTimeInterval remainingTime = self.dnsUpdateTimeout;
NSDate* startTime = [NSDate date];
err = DNSServiceQueryRecord(&sdRef, 0, 0,
host,
kDNSServiceType_SRV,
kDNSServiceClass_IN,
processDnsReply,
&remainingTime);
// This is necessary so we don't hang forever if there are no results
int dns_sd_fd = DNSServiceRefSockFD(sdRef);
int nfds = dns_sd_fd + 1;
fd_set readfds;
int result;
while (remainingTime > 0)
{
FD_ZERO(&readfds);
FD_SET(dns_sd_fd, &readfds);
struct timeval tv;
tv.tv_sec = (time_t)remainingTime;
tv.tv_usec = (remainingTime - tv.tv_sec) * 1000000;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result == 1)
{
if (FD_ISSET(dns_sd_fd, &readfds))
{
err = DNSServiceProcessResult(sdRef);
if (err != kDNSServiceErr_NoError)
{
NSLog(#"There was an error reading the DNS SRV records.");
break;
}
}
}
else if (result == 0)
{
NBLog(#"DNS SRV select() timed out");
break;
}
else
{
if (errno == EINTR)
{
NBLog(#"DNS SRV select() interrupted, retry.");
}
else
{
NBLog(#"DNS SRV select() returned %d errno %d %s.", result, errno, strerror(errno));
break;
}
}
NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startTime];
remainingTime -= elapsed;
}
DNSServiceRefDeallocate(sdRef);
}
}
static void processDnsReply(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char* fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void* rdata,
uint32_t ttl,
void* context)
{
NSTimeInterval* remainingTime = (NSTimeInterval*)context;
// If a timeout occurs the value of the errorCode argument will be
// kDNSServiceErr_Timeout.
if (errorCode != kDNSServiceErr_NoError)
{
return;
}
// The flags argument will have the kDNSServiceFlagsAdd bit set if the
// callback is being invoked when a record is received in response to
// the query.
//
// If kDNSServiceFlagsAdd bit is clear then callback is being invoked
// because the record has expired, in which case the ttl argument will
// be 0.
if ((flags & kDNSServiceFlagsMoreComing) == 0)
{
*remainingTime = 0;
}
// Record parsing code below was copied from Apple SRVResolver sample.
NSMutableData * rrData = [NSMutableData data];
dns_resource_record_t * rr;
uint8_t u8;
uint16_t u16;
uint32_t u32;
u8 = 0;
[rrData appendBytes:&u8 length:sizeof(u8)];
u16 = htons(kDNSServiceType_SRV);
[rrData appendBytes:&u16 length:sizeof(u16)];
u16 = htons(kDNSServiceClass_IN);
[rrData appendBytes:&u16 length:sizeof(u16)];
u32 = htonl(666);
[rrData appendBytes:&u32 length:sizeof(u32)];
u16 = htons(rdlen);
[rrData appendBytes:&u16 length:sizeof(u16)];
[rrData appendBytes:rdata length:rdlen];
rr = dns_parse_resource_record([rrData bytes], (uint32_t) [rrData length]);
// If the parse is successful, add the results.
if (rr != NULL)
{
NSString *target;
target = [NSString stringWithCString:rr->data.SRV->target encoding:NSASCIIStringEncoding];
if (target != nil)
{
uint16_t priority = rr->data.SRV->priority;
uint16_t weight = rr->data.SRV->weight;
uint16_t port = rr->data.SRV->port;
[[FailoverWebInterface sharedInterface] addDnsServer:target priority:priority weight:weight port:port ttl:ttl]; // You'll have to do this in with your own method.
}
}
dns_free_resource_record(rr);
}
Here's the Apple SRVResolver sample from which I got the RR parsing.
This Apple sample mentions that it may block forever, but strange enough suggest to use NSTimer when trying to add a timeout yourself. But I think using select() is a much better way.
I have one to-do: Implement flushing cache with DNSServiceReconfirmRecord. But won't do that now.
Be aware, this code is working, but I'm still testing it.
You need to add libresolv.dylib to your Xcode project's 'Linked Frameworks and Libraries'.
I have been trying to produce a "flv" video file in the following sequence:
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, "6.mp4", NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, "input_file.mp4", 0);
// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1; // Could not open codec
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate an AVFrame structure
pFrameYUV420 = avcodec_alloc_frame();
if (pFrameYUV420 == NULL)
return -1;
// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
// Assign appropriate parts of buffer to image planes in pFrameYUV420
// Note that pFrameYUV420 is an AVFrame, but AVFrame is a superset of AVPicture
avpicture_fill((AVPicture *) pFrameRGB, buffer, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
// Setup scaler
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, SWS_BILINEAR, 0, 0, 0);
if (img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context!\n");
exit(1);
}
// Setup encoder/muxing now
filename = "output_file.flv";
fmt = av_guess_format("flv", filename, NULL);
if (fmt == NULL) {
printf("Could not guess format.\n");
return -1;
}
/* allocate the output media context */
oc = avformat_alloc_context();
if (oc == NULL) {
printf("could not allocate context.\n");
return -1;
}
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
video_st = NULL;
if (fmt->video_codec != AV_CODEC_ID_NONE) {
video_st = add_stream(oc, &video_codec, fmt->video_codec);
}
// Let's see some information about our format
av_dump_format(oc, 0, filename, 1);
/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open '%s': %s\n", filename, av_err2str(ret));
return 1;
}
}
/* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file: %s\n", av_err2str(ret));
return 1;
}
// Setup x264 params
x264_param_t param;
x264_param_default_preset(¶m, "veryfast", "zerolatency");
param.i_threads = 1;
param.i_width = video_st->codec->width;
param.i_height = video_st->codec->height;
param.i_fps_num = STREAM_FRAME_RATE; // 30 fps, same as video
param.i_fps_den = 1;
// Intra refres:
param.i_keyint_max = STREAM_FRAME_RATE;
param.b_intra_refresh = 1;
// Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 25;
param.rc.f_rf_constant_max = 35;
// For streaming:
param.b_repeat_headers = 1;
param.b_annexb = 1;
x264_param_apply_profile(¶m, "baseline");
x264_t* encoder = x264_encoder_open(¶m);
x264_picture_t pic_in, pic_out;
x264_picture_alloc(&pic_in, X264_CSP_I420, video_st->codec->width, video_st->codec->height);
x264_nal_t* nals;
int i_nals;
// The loop:
// 1. Read frames
// 2. Decode the frame
// 3. Attempt to re-encode using x264
// 4. Write the x264 encoded frame using av_interleaved_write_frame
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if (frameFinished) {
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pic_in.img.plane, pic_in.img.i_stride);
int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
if (frame_size >= 0) {
if (i_nals < 0)
printf("invalid frame size: %d\n", i_nals);
// write out NALs
for (i = 0; i < i_nals; i++) {
// initalize a packet
AVPacket p;
av_init_packet(&p);
p.data = nals[i].p_payload;
p.size = nals[i].i_payload;
p.stream_index = video_st->index;
p.flags = AV_PKT_FLAG_KEY;
p.pts = AV_NOPTS_VALUE;
p.dts = AV_NOPTS_VALUE;
ret = av_interleaved_write_frame(oc, &p);
}
}
printf("encoded frame #%d\n", frame_count);
frame_count++;
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Now we free up resources used/close codecs, and finally close our program.
Here is the implementation for the add_stream() function:
/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id) {
AVCodecContext *c;
AVStream *st;
int r;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
fprintf(stderr, "Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
exit(1);
}
st = avformat_new_stream(oc, *codec);
if (!st) {
fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
st->id = oc->nb_streams - 1;
c = st->codec;
switch ((*codec)->type) {
case AVMEDIA_TYPE_AUDIO:
st->id = 1;
c->sample_fmt = AV_SAMPLE_FMT_FLTP;
c->bit_rate = 64000;
c->sample_rate = 44100;
c->channels = 2;
break;
case AVMEDIA_TYPE_VIDEO:
avcodec_get_context_defaults3(c, *codec);
c->codec_id = codec_id;
c->bit_rate = 500*1000;
//c->rc_min_rate = 500*1000;
//c->rc_max_rate = 500*1000;
//c->rc_buffer_size = 500*1000;
/* Resolution must be a multiple of two. */
c->width = 1280;
c->height = 720;
/* timebase: This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
c->time_base.den = STREAM_FRAME_RATE;
c->time_base.num = 1;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
c->max_b_frames = 2;
}
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
/* Needed to avoid using macroblocks in which some coeffs overflow.
* This does not happen with normal video, it just happens here as
* the motion of the chroma plane does not match the luma plane. */
c->mb_decision = 2;
}
break;
default:
break;
}
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
After the encoding is complete, I check the output file output_file.flv. I notice it's size is very large: 101MB and it does not play. If I use ffmpeg to decode/encode the input file, then I get an output file about 83MB in size (which is about the same size as the original .mp4 file used as input). Also, the 83MB output from just using ffmpeg C api, as opposed to using x264 for the encoding step, plays just fine. Does anyone know where I am going wrong? I have tried researching this for a few days now but with no luck :(. I feel that I am close to making it work, however, I just cannot figure out what I am doing wrong. Thank you!
To produce the correct AVPacket, you should write all nals into the same packet, as it is done in http://ffmpeg.org/doxygen/trunk/libx264_8c_source.html (see encode_nals and X264_frame functions)
I just cann't seem to get the FFMpeg working with using the library. Everytime I try to convert asf file to wmv. I get the following issue on run time:
[wmv1 # 0x81ee000]error, slice code was 2
[wmv1 # 0x81ee000]header damaged
This my code:
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len, in_size;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_WMV1);
if (!codec) {
fprintf(stderr, "codec not found\n");
return;
}
c= avcodec_alloc_context2(CODEC_TYPE_AUDIO);
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
return;
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
return;
}
/* decode until eof */
avpkt.data = inbuf;
len = avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
NSLog(#"%d", avpkt.size);
while (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio2(c, (short *)outbuf, &out_size, inbuf,len);// avpkt.size);
NSLog(#"%d", len);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
fclose(outfile);
return;
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
fwrite(outbuf, 1, out_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
I have try the command line utilities and it successfully convert the file. Any help would be helpfully. thanks
Make the mistake of opening the wrong file