[Libav-user] h264 / aac in quicktime container, no audio in quicktime

Kam kam187 at gmail.com
Tue Feb 16 11:57:30 CET 2016


Hello,

I'm pulling out my hair trying to get a h264 and aac (raw with no adts)
into a quicktime container (or mp4 - same results).  The video works fine,
but the audio does not play at all in quicktime.  In fact when i view media
information it only shows h264 and there is no entry for AAC at all.

The same video works fine in VLC and my time stamps are all correct.  I
have already tried rescaling the timestamps or increasing them in even
1/fps steps (as a test of course) and qt still doesn't see the audio.

See code below:

// Video has a uin64_t ntp timestamp, so the numerator would usually be 1
and the denominator would usually be 2^32
// Because ffmpeg uses an int64 / int32 we need to divide the 64bit ntp ts
by at least 2 to handle the sign bit.
// I'll divide it by 65536 (and lose some precision) so we have enough
space in the numerator to store a long video
double iCMTimeNumeratorDivider = 0x10000;
double iCMTimeDenomentator     = 4294967296/iCMTimeNumeratorDivider;

struct connection { // Convenient way to pass all the connection vars
between functions
AVFormatContext *oc; // AV Output context
int FFaudioStreamIndex;
int FFvideoStreamIndex;
// Stream
struct timeval streamStartTime; // The time we received the first packet
// Video
uint64_t firstVideoTimeStamp; // Initial timestamp to calculate offsets

// Audio
bool firstAudioPacket; // Signal this is the first audio packet (new
connection)
uint16_t prevAudioSequence; // Previous Audio sequence number
uint64_t longAudioTimeStamp; // 64 bit timestamp
};

// When the data arrives on a new connection i create the file and add the
streams
void createFile(struct connection *c, unsigned char *configData, int
configLen) {
//av_log_set_level(AV_LOG_DEBUG);
av_log_set_level(AV_LOG_TRACE);

char filename[255]; // filename
strcpy(filename, "test.mov");
avformat_alloc_output_context2(&c->oc, NULL, NULL, filename);
if (!c->oc)
        terminateGracefully(c, "Could not create output context
(libavformat).");

// Setup the video stream
uint32_t streamWidth = 0;
uint32_t streamHeight = 0;
decodeSPS(c, configData, &streamWidth, &streamHeight); // decode the SPS
and extract the stream width and height
AVStream *videoStream = avformat_new_stream(c->oc, NULL);
if (!videoStream)
        terminateGracefully(c, "ERROR creating video stream.");

c->FFvideoStreamIndex = c->oc->nb_streams-1;
videoStream->id = c->FFvideoStreamIndex;
    videoStream->time_base.num = 1;
    videoStream->time_base.den = iCMTimeDenomentator; // Denominator is now
2^32 divided by 65536, i'll divide pts by 65536 too

    videoStream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
    videoStream->codec->codec_id = AV_CODEC_ID_H264;
    videoStream->codec->width = streamWidth;
    videoStream->codec->height = streamHeight;
//videoStream->codec->pix_fmt = AV_PIX_FMT_YUV420P16;

// Copy extra data
videoStream->codec->extradata = (uint8_t*)av_mallocz(configLen);
videoStream->codec->extradata_size = configLen;
memcpy(videoStream->codec->extradata, configData, configLen);

// Setup the audio stream
AVStream *audioStream = avformat_new_stream(c->oc, NULL);
if (!audioStream)
        terminateGracefully(c, "ERROR creating audio stream.");

c->FFaudioStreamIndex = c->oc->nb_streams-1; // 16 bit 44,100Hz AAC
audioStream->id = c->FFaudioStreamIndex;
audioStream->time_base.num = 1;
audioStream->time_base.den = 44100;

audioStream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
audioStream->codec->codec_id = AV_CODEC_ID_AAC;
audioStream->codec->sample_rate = 44100;

audioStream->codec->channel_layout = AV_CH_LAYOUT_STEREO;
audioStream->codec->sample_fmt = AV_SAMPLE_FMT_S16;
audioStream->codec->channels = 2;
audioStream->codec->frame_size = 1024;
audioStream->codec->profile = FF_PROFILE_AAC_LOW;
// audioStream->codec->profile = FF_PROFILE_AAC_MAIN;

// We need global flags for qt
    if (c->oc->oformat->flags & AVFMT_GLOBALHEADER) {
        videoStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
        audioStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }

// Create the file
    if (!(c->oc->oformat->flags & AVFMT_NOFILE))
        if (avio_open(&c->oc->pb, c->oc->filename, AVIO_FLAG_WRITE) < 0)
terminateGracefully(c, "Error opening file");

// Write the headers
AVDictionary * av_opts = NULL;
av_dict_set(&av_opts, "movflags", "faststart+disable_chpl", 0);
avformat_write_header(c->oc, &av_opts); //, NULL);

av_dump_format(c->oc, 0, filename, 1);
printf("Video stream index %d, id = %d\n", videoStream->index,
videoStream->id);
printf("Audio stream index %d, id = %d\n", audioStream->index,
audioStream->id);
}

void processAudio(struct connection *c, uint32_t len) {
if (c->streamStartTime.tv_sec == 0) gettimeofday(&c->streamStartTime, NULL); //
Setup the stream start time to 'NOW' in system time if it's not already set

// Audio data has a rtp header
// 80 96 = Version(2) | Padding (1) | Extension (1) | CC/CSRC count (4) |
Marker (1) | Payload Type (7)
// b191 = sequence number
// f7 79 16 c2 = Timestamp
// e8 bb 6b 2c = Sync source identifer
// 00 00 00 00 = SSRC
// 00 00 00 00 = CSRC
uint32_t seq = (c->audioBuffer[2]<<8 | c->audioBuffer[3]); // Get reversed
uint16 seq

// If this is the
// Audio has an rtp timestamp. So i'll use NOW (in system time) minus the
video start time (in system time) as an index of how much time has passed
till now
// Then store that as increments of timebase to setup the initial timestamp
offset for the audio

if (c->firstAudioPacket) { // Init previous sequence on first packet
c->firstAudioPacket = false;
c->prevAudioSequence = seq;
// Init the audio timestamp to 'NOW'
struct timeval timeNow;
gettimeofday(&timeNow,NULL);
c->longAudioTimeStamp = (timeNow.tv_sec - c->streamStartTime.tv_sec)*44100
+ (timeNow.tv_usec - c->streamStartTime.tv_usec)*0.044100;
}
c->longAudioTimeStamp += ( (seq - c->prevAudioSequence)*1024 ); //
Increment long ts in sample size increments
c->prevAudioSequence = seq; // Store this as the previous ts

len -= 12; // Strip header
AVPacket packet;
av_init_packet(&packet); // Init the packet with defaults
packet.pts = c->longAudioTimeStamp; // Calculated offset pts
packet.dts = AV_NOPTS_VALUE;

// packet.duration = 1024;
packet.stream_index = c->FFaudioStreamIndex; // Audio stream index
packet.data =  c->daudioBuffer; // Set the data pointer
packet.size =  len; // Set the length

printf("----------> Audio: %f\n",
(double)packet.pts/(double)c->oc->streams[c->FFaudioStreamIndex]->time_base.den);
av_interleaved_write_frame(c->oc, &packet); // Write it interleaved
avio_flush(c->oc->pb);
}

void processVideo(struct connection *c, uint32_t len) {

...

if (c->streamStartTime.tv_sec == 0) gettimeofday(&c->streamStartTime, NULL); //
Setup the stream start time if it's not already set

uint64_t ts = *(uint64_t *)&c->videoBuffer[o + 8];

// Setup initial ts to calculate offsets
if (c->firstVideoTimeStamp == 0) {
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
c->firstVideoTimeStamp = ts - (timeNow.tv_sec -
c->streamStartTime.tv_sec)*4294967296 - (timeNow.tv_usec -
c->streamStartTime.tv_usec)*4294.967296;
}

AVPacket packet;
av_init_packet(&packet); // Init the packet with defaults
packet.pts = (ts - c->firstVideoTimeStamp)/iCMTimeNumeratorDivider; //
Calculate offset pts
packet.dts = AV_NOPTS_VALUE;
packet.stream_index = c->FFvideoStreamIndex; // Video stream index
packet.data =  &c->videoBuffer[o + NALU_HEADER_LEN]; // Set the data pointer
packet.size =  len; // Set the length

printf("Video: %lu, %f\n", ts,
(double)packet.pts/(double)c->oc->streams[c->FFvideoStreamIndex]->time_base.den);

av_interleaved_write_frame(c->oc, &packet); // Write it interleaved
avio_flush(c->oc->pb); // Flush to disk (for testing)

...
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20160216/5f3f674c/attachment.html>


More information about the Libav-user mailing list