Skip to content

Commit

Permalink
feat: read/write mp3 audio
Browse files Browse the repository at this point in the history
  • Loading branch information
ireader committed Nov 13, 2020
1 parent f0880ef commit 68da241
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 21 deletions.
4 changes: 2 additions & 2 deletions libmov/source/mov-stsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ static int mov_read_video(struct mov_t* mov, struct mov_sample_entry_t* entry)
}

/*
class PixelAspectRatioBox extends Box(‘pasp’){
class PixelAspectRatioBox extends Box(‘pasp?{
unsigned int(32) hSpacing;
unsigned int(32) vSpacing;
}
Expand Down Expand Up @@ -471,7 +471,7 @@ static size_t mov_write_audio(const struct mov_t* mov, const struct mov_sample_e
// 2. The samplerate field shall be set to 48000<<16.
mov_buffer_w32(&mov->io, entry->u.audio.samplerate); /* samplerate */

if(MOV_OBJECT_AAC == entry->object_type_indication)
if(MOV_OBJECT_AAC == entry->object_type_indication || MOV_OBJECT_MP3 == entry->object_type_indication || MOV_OBJECT_MP1A == entry->object_type_indication)
size += mov_write_esds(mov);
else if(MOV_OBJECT_OPUS == entry->object_type_indication)
size += mov_write_dops(mov);
Expand Down
2 changes: 2 additions & 0 deletions libmov/source/mov-tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ static struct mov_object_tag s_tags[] = {
{ MOV_OBJECT_HEVC, MOV_TAG('h', 'e', 'v', '1') }, // HEVCSampleEntry (ISO/IEC 14496-15:2013)
{ MOV_OBJECT_MP4V, MOV_MP4V },
{ MOV_OBJECT_AAC, MOV_MP4A },
{ MOV_OBJECT_MP3, MOV_MP4A }, // mp4_read_decoder_config_descriptor
{ MOV_OBJECT_MP1A, MOV_MP4A }, // mp4_read_decoder_config_descriptor
{ MOV_OBJECT_G711a, MOV_TAG('a', 'l', 'a', 'w') },
{ MOV_OBJECT_G711u, MOV_TAG('u', 'l', 'a', 'w') },
{ MOV_OBJECT_TEXT, MOV_TAG('t', 'x', '3', 'g') },
Expand Down
3 changes: 3 additions & 0 deletions libmov/source/mov-track.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ int mov_add_audio(struct mov_track_t* track, const struct mov_mvhd_t* mvhd, uint
{
struct mov_sample_entry_t* audio;

if (MOV_OBJECT_MP3 == object && sample_rate > 24000)
object = MOV_OBJECT_MP1A; // use mpeg1 sample rate table, see more @libflv/source/mp3-header.c

audio = &track->stsd.entries[0];
audio->data_reference_index = 1;
audio->object_type_indication = object;
Expand Down
16 changes: 15 additions & 1 deletion libmov/test/mov-reader-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static uint32_t s_av1_track = 0xFFFFFFFF;
static uint32_t s_vpx_track = 0xFFFFFFFF;
static uint32_t s_hevc_track = 0xFFFFFFFF;
static uint32_t s_opus_track = 0xFFFFFFFF;
static uint32_t s_mp3_track = 0xFFFFFFFF;

inline const char* ftimestamp(uint32_t t, char* buf)
{
Expand Down Expand Up @@ -97,6 +98,13 @@ static void onread(void* flv, uint32_t track, const void* buffer, size_t bytes,
a_pts = pts;
a_dts = dts;
}
else if (s_mp3_track == track)
{
printf("[MP3] pts: %s, dts: %s, diff: %03d/%03d, bytes: %u\n", ftimestamp(pts, s_pts), ftimestamp(dts, s_dts), (int)(pts - a_pts), (int)(dts - a_dts), (unsigned int)bytes);
a_pts = pts;
a_dts = dts;
fwrite(buffer, 1, bytes, s_afp);
}
else
{
printf("text\n");
Expand Down Expand Up @@ -138,9 +146,9 @@ static void mov_video_info(void* /*param*/, uint32_t track, uint8_t object, int

static void mov_audio_info(void* /*param*/, uint32_t track, uint8_t object, int channel_count, int /*bit_per_sample*/, int sample_rate, const void* extra, size_t bytes)
{
s_afp = fopen("a.aac", "wb");
if (MOV_OBJECT_AAC == object)
{
s_afp = fopen("a.aac", "wb");
s_aac_track = track;
assert(bytes == mpeg4_aac_audio_specific_config_load((const uint8_t*)extra, bytes, &s_aac));
assert(channel_count == s_aac.channels);
Expand All @@ -151,10 +159,16 @@ static void mov_audio_info(void* /*param*/, uint32_t track, uint8_t object, int
}
else if (MOV_OBJECT_OPUS == object)
{
s_afp = fopen("a.opus", "wb");
s_opus_track = track;
assert(bytes == opus_head_load((const uint8_t*)extra, bytes, &s_opus));
assert(s_opus.input_sample_rate == 48000);
}
else if (MOV_OBJECT_MP3 == object || MOV_OBJECT_MP1A == object)
{
s_afp = fopen("a.mp3", "wb");
s_mp3_track = track;
}
else
{
s_aac_track = track;
Expand Down
48 changes: 30 additions & 18 deletions libmov/test/mov-writer-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "mov-udta.h"
#include "mpeg4-aac.h"
#include "opus-head.h"
#include "mp3-header.h"
#include "flv-proto.h"
#include "flv-reader.h"
#include "flv-parser.h"
Expand All @@ -20,59 +21,70 @@ static int s_width, s_height;
static int onFLV(void* param, int codec, const void* data, size_t bytes, uint32_t pts, uint32_t dts, int flags)
{
mov_writer_t* mov = (mov_writer_t*)param;
static int s_aac_track = -1;
static int s_avc_track = -1;
static int s_opus_track = -1;
static int s_audio_track = -1;
static int s_video_track = -1;

switch(codec)
{
case FLV_AUDIO_AAC:
return mov_writer_write(mov, s_aac_track, data, bytes, pts, dts, 1==flags ? MOV_AV_FLAG_KEYFREAME : 0);
return mov_writer_write(mov, s_audio_track, data, bytes, pts, dts, 1==flags ? MOV_AV_FLAG_KEYFREAME : 0);

case FLV_AUDIO_OPUS:
return mov_writer_write(mov, s_opus_track, data, bytes, pts, dts, 1 == flags ? MOV_AV_FLAG_KEYFREAME : 0);
return mov_writer_write(mov, s_audio_track, data, bytes, pts, dts, 1 == flags ? MOV_AV_FLAG_KEYFREAME : 0);

case FLV_AUDIO_MP3:
assert(0);
break;
if (-1 == s_audio_track)
{
struct mp3_header_t mp3;
if (0 == mp3_header_load(&mp3, data, bytes))
return -1;
s_audio_track = mov_writer_add_audio(mov, MOV_OBJECT_MP3, mp3_get_channel(&mp3), 16, mp3_get_frequency(&mp3), NULL, 0);
}

if (-1 == s_audio_track)
return -1;
return mov_writer_write(mov, s_audio_track, data, bytes, pts, dts, 1 == flags ? MOV_AV_FLAG_KEYFREAME : 0);

case FLV_VIDEO_H264:
case FLV_VIDEO_H265:
case FLV_VIDEO_AV1:
return mov_writer_write(mov, s_avc_track, data, bytes, pts, dts, flags);
return mov_writer_write(mov, s_video_track, data, bytes, pts, dts, flags);

case FLV_VIDEO_AVCC:
if (-1 == s_avc_track)
s_avc_track = mov_writer_add_video(mov, MOV_OBJECT_H264, s_width, s_height, data, bytes);
if (-1 == s_video_track)
s_video_track = mov_writer_add_video(mov, MOV_OBJECT_H264, s_width, s_height, data, bytes);
break;

case FLV_VIDEO_HVCC:
if (-1 == s_avc_track)
s_avc_track = mov_writer_add_video(mov, MOV_OBJECT_HEVC, s_width, s_height, data, bytes);
if (-1 == s_video_track)
s_video_track = mov_writer_add_video(mov, MOV_OBJECT_HEVC, s_width, s_height, data, bytes);
break;

case FLV_VIDEO_AV1C:
if (-1 == s_avc_track)
s_avc_track = mov_writer_add_video(mov, MOV_OBJECT_AV1, s_width, s_height, data, bytes);
if (-1 == s_video_track)
s_video_track = mov_writer_add_video(mov, MOV_OBJECT_AV1, s_width, s_height, data, bytes);
break;

case FLV_AUDIO_ASC:
if (-1 == s_aac_track)
if (-1 == s_audio_track)
{
struct mpeg4_aac_t aac;
mpeg4_aac_audio_specific_config_load((const uint8_t*)data, bytes, &aac);
int rate = mpeg4_aac_audio_frequency_to((enum mpeg4_aac_frequency)aac.sampling_frequency_index);
s_aac_track = mov_writer_add_audio(mov, MOV_OBJECT_AAC, aac.channel_configuration, 16, rate, data, bytes);
s_audio_track = mov_writer_add_audio(mov, MOV_OBJECT_AAC, aac.channel_configuration, 16, rate, data, bytes);
}
break;
case FLV_AUDIO_OPUS_HEAD:
if (-1 == s_opus_track)
if (-1 == s_audio_track)
{
struct opus_head_t opus;
opus_head_load((const uint8_t*)data, bytes, &opus);
s_opus_track = mov_writer_add_audio(mov, MOV_OBJECT_OPUS, opus.channels, 16, opus.input_sample_rate, data, bytes);
s_audio_track = mov_writer_add_audio(mov, MOV_OBJECT_OPUS, opus.channels, 16, opus.input_sample_rate, data, bytes);
}
break;

case 0: // script
break;
default:
// nothing to do
assert(0);
Expand Down

0 comments on commit 68da241

Please sign in to comment.