I implemented a network video player (like VLC) using ffmpeg. But it can not decode AAC audio stream received from a IP camera. It can decode other audio sterams like G711, G726 etc. I set the codec ID as AV_CODEC_ID_AAC and I set channels and sample rate of AvCodecContext. But avcodec_decode_audio4 fails with an error code of INVALID_DATA. I checked previously asked questions, I tried to add extrabytes to AvCodecContext using media format specific parameters of "config=1408". And I set extradatabytes as 2 bytes of "20" and "8" but it also not worked. I appreciate any help, thanks.
IP CAMERA SDP:
a=rtpmap:96 mpeg4-generic/16000/1
a=fmtp:96 streamtype=5; profile-level-id=5; mode=AAC-hbr; config=1408; SizeLength=13; IndexLength=3; IndexDeltaLength=3
AVCodec* decoder = avcodec_find_decoder((::AVCodecID)id);//set as AV_CODEC_ID_AAC
AVCodecContext* decoderContext = avcodec_alloc_context3(decoder);
char* test = (char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi("1408").ToPointer();
unsigned int length;
uint8_t* extradata = parseGeneralConfigStr(test, length);//it is set as 0x14 and 0x08
decoderContext->channels = number_of_channels; //set as 1
decoderContext->sample_rate = sample_rate; //set as 16000
decoderContext->channel_layout = AV_CH_LAYOUT_MONO;
decoderContext->codec_type = AVMEDIA_TYPE_AUDIO;
decoderContext->extradata = (uint8_t*)av_malloc(AV_INPUT_BUFFER_PADDING_SIZE + length);
memcpy(decoderContext->extradata, extradata, length);
memset(decoderContext->extradata+ length, 0, AV_INPUT_BUFFER_PADDING_SIZE);
Did you check data for INVALID_DATA?
You can check it according to RFC
RFC3640 (3.2 RTP Payload Structure)
AAC Payload can be seperated like below
AU-Header | Size Info | ADTS | Data
Example payload 00 10 0c 00 ff f1 60 40 30 01 7c 01 30 35 ac
According to configs that u shared
AU-size (SizeLength=13)
AU-Index / AU-Index-delta (IndexLength=3/IndexDeltaLength=3)
The length in bits of AU-Header is 13(SizeLength) + 3(IndexLength/IndexDeltaLength) = 16.
AU-Header 00 10
You should use AU-size(SizeLength) value for Size Info
AU-size: Indicates the size in octets of the associated Access Unit in the Access Unit Data Section in the same RTP packet.
First 13 (SizeLength) bits 0000000000010 equals to 2. So read 2 octets for size info.
Size Info 0c 00
ADTS ff f1 60 40 30 01 7c
ADTS Parser
ID MPEG-4
MPEG Layer 0
CRC checksum absent 1
Profile Low Complexity profile (AAC LC)
Sampling frequency 16000
Private bit 0
Channel configuration 1
Original/copy 0
Home 0
Copyright identification bit 0
Copyright identification start 0
AAC frame length 384
ADTS buffer fullness 95
No raw data blocks in frame 0
Data starts with 01 30 35 ac.
Related
I am working on an mp3 decoder, the formula to determine the length, in bytes, of an mp3 frame is
FrameSize = 144 * BitRate / (SampleRate + Padding)
I can't find anywhere that explains what the '144' represents.
Does anyone know?
The 144 represents total bytes-per-frame.
MP3 files are generally encoded as MPEG-1 Layer 3.
There are 1152 samples per frame in type Layer 3.
1152 samples / 8 bits-per-byte = 144 bytes total.
Taking the formula for frame size (in bytes):
FrameSize = 144 * BitRate / (SampleRate + Padding)
We can see (for MP3 with 192 bitrate # 44.1 khz):
144 * 192 / (44.1 + 0) = 626 bytes per audio frame (fraction parts are ignored).
I have written the following code to print the data in Pin and Pout to a file:
void run() {
while ( in.readable() >= 17*11*12+SIZE_RSPACKET &&
out.writable() >= 1 ) {
u8 *pin = in.rd()+17*11*12, *pend=pin+SIZE_RSPACKET;
u8 *pout= out.wr()->data;
for ( int delay=17*11; pin<pend;
++pin,++pout,delay=(delay-17+17*12)%(17*12) )
*pout = pin[-delay*12];
in.read(SIZE_RSPACKET);
out.written(1);
/* Printing output after Deinterleaving to file: Need to Turn this into Binary */
FILE * F; // Create File
F = fopen("Deinterleaving.txt", "wb"); // Open Deinterleaving File
for(int i = 0; i < SIZE_RSPACKET; i++){ // For Every Packet (204 bytes)
// Print char for data coming and going out (Not Binary) to file
fprintf(F, "%s %u %s %u \n", " Data coming in: ", pin[i], " Data Going Out: ", pout[i]);
}
fflush(F);
fclose(F);
}
}
This gives me the output:
Data coming in: 71 Data Going Out: 0
Data coming in: 99 Data Going Out: 0
Data coming in: 46 Data Going Out: 0
Data coming in: 84 Data Going Out: 0
Data coming in: 129 Data Going Out: 0
Data coming in: 134 Data Going Out: 0
Data coming in: 1 Data Going Out: 0
Data coming in: 101 Data Going Out: 0
Data coming in: 15 Data Going Out: 1
How can I convert this to it's binary counterpart for every 8 packets so that the output will look like the following?
What the output should look like (i.e. 1 block (8 Packets of 204 bytes each)):
71 99 46 84 129 134 1 101 -> 01000111 01100011 0101110 01010100 010000001 010000110 00000001 01100101
Use fwrite for writing internal representation of data to a file:
fwrite(&pin[0], 1, sizeof(pin), F);
Also, open the file in a binary mode to avoid translations, such as the value 0x0d being replaced by 0x0d, 0x0a.
The fprintf is for transforming internal representation into human readable form.
I known there is a lot of question about status printer ...
i have a Citizen CT-S310 II, i have managed all the code for write character in USB without problem with libusb_bulk_transfer (Text, Bold, Center, CR, CUT_PAPER etc) :
#define ENDPOINT_OUT 0x02
#define ENDPOINT_IN 0x81
struct libusb_device_handle *_handle;
[detach kernel driver...]
[claim interface...]
[etc ...]
r = libusb_bulk_transfer(device_handle, ENDPOINT_OUT, Mydata, out_len, &transferred, 1000);
Now, i need to receive data from the printer to ckeck the status, my first idea was to send the POS command with the same "bulk_transfer" of the doc :
1D (hexa) 72 (hexa) n
n => 1 (Send the papel sensor status)
and retrieve the value by "bulk_transfer" with the end point "ENDPOINT_IN" the doc say there is 8 bytes to receive :
bit 0,1 => paper found by paper near-end sensor 00H
bit 0,1 => paper not found by paper near-end sensor 03H
bit 1,2 => paper found by paper-end sensor 00H
bit 1,2 => paper not found by paper-end sensor 0CH
[...]
so two "bulk_transfer", one for send command status (ENDPOINT_OUT) and one for receive the result (ENDPOINT_IN), but i have allways an USB ERROR ("bulk_transfer" in read = -1)
Maybe the USB don't work like this ? So my second idea was to use the implemented function in PrinterClass USB with the command "control_transfer" :
int r = 0;
int out_len = 1;
unsigned char* _udata = NULL;
uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE;
uint8_t bRequest = LIBUSB_REQUEST_GET_STATUS;
uint16_t wValue = 0; // the value field for the setup packet (?????)
uint16_t wIndex = 0; // N° interface printer (the index field for the setup packet)
r = libusb_control_transfer(device_handle, bmRequestType,bRequest,wValue, wIndex,_udata,out_len, USB_TIMEOUT);
i don't exactly how to fill all the parameter, i know it depend of my device, but the doc of libsub is not very explicit.
What is exactly "wValue" ?
What is exactly "wIndex" ? the interface number ??
the parameter LIBUSB_ENDPOINT_IN by default is 0x80, but my printer use 0x81, i must to change this default endpoint ?
Bus 001 Device 004: ID 1d90:2060
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1d90
idProduct 0x2060
bcdDevice 0.02
iManufacturer 1 CITIZEN
iProduct 2 Thermal Printer
iSerial 3 00000000
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 7 Printer
bInterfaceSubClass 1 Printer
bInterfaceProtocol 2 Bidirectional
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0001
Self Powered
The response of "control_transfer" in my case is always 0 :( with paper or without.How send a good "control_transfer" for request the status of my printer ??
All the help for solve my problem is welcome !!!
finally resolved !
The value of LIBUSB_REQUEST_GET_STATUS is 0x00, but for a printer the request status is 0x01.
for check the status of printer with libusb-1.0 :
uint8_t bmRequestType = LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE;
uint8_t bRequest = 0x01; // Here not LIBUSB_REQUEST_GET_STATUS
uint16_t wValue = 0;
uint16_t wIndex = 0;
r = libusb_control_transfer(device_handle, bmRequestType,bRequest,wValue, wIndex,&_udata,out_len, USB_TIMEOUT);
Excuse me for my bad english. I have a number in the decimal system: 0.15625.
(This is example) http://www.strozhevsky.com/free_docs/asn1_in_simple_words.pdf (Page 5)
By the rule of BER ASN.1 - Encoded in octal: 09 03 90 FE 0A (This is the right decision)
http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf -
Standart ASN.1(8.5 - REAL)
1 byte:
(8-7) Class - Universal - 00
(6) P/C - Primitive - 0
(5-1) Tag Number - 01001(REAL)
TOTAL: 00001001(2) = 09(16) (Correct)
2 byte:
(8) binary encoding - 1
_____________________
(7) When binary encoding is used (bit 8 = 1), then if the mantissa M is
non-zero, it shall be represented by a sign S, a positive integer value N
and a binary scaling factor F, such that:
M = S × N × 2F
Bit 7 of the first contents octets shall be 1 if S is –1 and 0 otherwise.
What I would have bit 7?
_____________________
(6-5) base 8 - 01
_______________________
(3-4) Bits 4 to 3 of the first contents octet shall encode the value of
the binary scaling factor F as an unsigned binary
integer. I don't have scaling factor. - 00
_____________________
(2-1) 8.5.6.4 Bits 2 to 1 of the first contents octet shall encode
the format of the exponent as follows: I do not know how to determine
what my value will be here. (Poor understand English). I think 11?
Total: 1?010011 - NOT EQUAL 03 Why? (Not correct)
What does the 90? Call octet? How to find it? The book does not say, or I simply do not understand.
In FE coded number -2(Exponent), how do I translate FE, not to get 254, and -2? Perhaps it contains information about the byte: 90?
Thank you for listening.
In the section "Chapter 1. Common rules for ASN.1 encoding" it states that an encoding has three sections:
an information block
a length block
a value block
The length block specifies the length of the value block.
The encoding of 0.15625 as the octets 09 03 80 FB 05 breaks down like this:
09 - information block (1 octet)
03 - length block (1 octet)
80 FB 05 - value block (3 octets)
The value block itself consists of three sections: an information octet, a block for the exponent and a block for the mantissa. In this case the mantissa is M = 5 (101 in base 2) and the exponent is E = -5. Therefore the value block is:
80 - information octet
FB - the exponent block (FB = -5)
05 - the mantissa block (5)
The information octet specifies various pieces of information including:
that we are encoding a real number
we are using in base 2, and
the number is non-negative (>= 0)
To answer your question about FE being interpreted as -2, this is how negative numbers are represented in 2s-complement arithmetic (more info). For single octet numbers we have:
FF -> -1
FE -> -2
FD -> -3
...
80 -> -128
7F -> +127
7E -> +126
I'm trying to send a protocol buffer message over TCP, but on the receiving side I'm getting a "Missing required fields" error when trying to parse, even though apparently all the fields are there. I'm sending a 4 byte header before the message that contains the length of the message.
Here is the message definition:
message ReplayRequest {
required string channel = 1;
required uint32 start = 2;
required uint32 end = 3;
}
On the client side I'm encoding the header and serializing the message into a vector.
ReplayRequest req;
req.set_channel( "channel" )
req.set_start( 1 );
req.set_end( 5 );
int byte_size = req.ByteSize();
std::vector<uint8_t> write_buffer( HEADER_SIZE + byte_size );
encode_header( ... );
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );
This is a hex print of the resulting buffer, where the first 4 bytes are the encoded message length (13 bytes).
00 00 00 0d 0a 07 63 68 61 6e 6e 65 6c 10 01 18 05
On the server side, I receive the header, decode it and then receive N bytes where N is the message size reported in the header. The buffer in the server with the header removed is:
0a 07 63 68 61 6e 6e 65 6c 10 01 18 05
Which is exactly the same as the one encoded client side minus the header, but when I try to ParseFromArray this buffer I get an error:
libprotobuf ERROR c:\umdf_runtime\protobuf-2.4.1\src\google\protobuf\message_lit
e.cc:123] Can't parse message of type "ReplayRequest" because it is missing
required fields: channel, start, end
While debugging I noticed that the point where decoding fails is on this part of the protobuf generated code:
bool ReplayRequest::IsInitialized() const {
if ((_has_bits_[0] & 0x00000007) != 0x00000007) return false;
return true;
}
has_bits_ is being read as zero on the server side for some reason but I can't figure out why.
Any ideas?
I'm using boost::asio for the network part if it matters.
Update
As requested I'm posting the code that calls parseFromArray.
request_.ParseFromArray( &data_buffer_, data_buffer_.size() );
request_ is a ReplayRequest member variable, up until this call nothing is done to it.
data_buffer_ is a vector<uint8_t> where the TCP data is received into.
I confirmed that it is correctly sized at 13 bytes and this is its hex dump, which is the same that I get when I dump the buffer client side after serializing.
0a 07 63 68 61 6e 6e 65 6c 10 01 18 05
Update 2
I am able to parse the buffer into another instance of ReplayRequest on the client side, i.e.:
...snip...
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );
ReplayRequest test;
test.ParseFromArray( &write_buffer[HEADER_SIZE], byte_size );
test is successfully populated with the correct fields.
The issue is that you're passing in a pointer to the vector and not a pointer to the vector's data.
instead of
request_.ParseFromArray( &data_buffer_, data_buffer_.size() );
try
request_.ParseFromArray( &data_buffer_[0], data_buffer_.size() );
Another solution if the required field is missing but not needed for you and if you cannot change that field to optional in the protofile, you could use ParsePartialFromArray instead of ParseFromArray.
See protobuf documentation: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message_lite