FC2ブログ

ホーム > AACファイルフォーマット > MP4ファイル音声の再生 第1部

MP4ファイル音声の再生 第1部



faad2ライブラリーを使用して、AACフォーマットで作成されたMP4ファイルの音声をデコード/再生するプログラムについて解説します。




MP4ファイルメタデータを読み込むためには、faad2-2.7のインストールで入手したライブラリの中のmp4ffプロジェクトが必要となります。VisualC++NET2008以上のバージョンがあればそのままでも使えますが、今までVisualC++NET2003で解説してきたので、敢えてVisualC++NET2003で新たにプロジェクトを作成します。

まずはVisualC++NET2003を起動し、メニューから「ファイル」/「新規」/「プロジェクト」を選択して、「新規プロジェクト」ダイヤログを表示させます。テンプレートは「Win32 Project」、プロジェクト名は「libmp4ff-vc7」、「ブラウズ」ボタンを押してプロジェクトフォルダーを作成するフォルダーを「faad2-2.7」と同じフォルダーに設定し、「OK」ボタンを押します。



「アプリケーションウィザード」の「アプリケーション設定」タブにて、アプリケーション形式は「Static Library」を選択し、追加オプションの「Precompiled Header」のチェックを外し、追加サポートの「MFC」のチェックも外してから「完了」ボタンを押します。



「libmp4ff-vc7」プロジェクトが作成され、内容がソリューションエクスプローラに表示されます。



ソリューションエクスプローラで「libmp4ff-vc7」プロジェクトを右クリックして、ポップアップメニューから「追加」→「既存ファイルの追加」を選択し、「faad2-2.7フォルダー」→「commonフォルダー」→「mp4ffフォルダー」にあるすべてのファイル(CPPファイルとヘッダーファイル)をプロジェクトに追加します。



ソリューションエクスプローラで「libmp4ff-vc7」プロジェクトを右クリックして、ポップアップメニューから「プロパティ」を選択し、「構成プロパティ」→「C++」→「コード生成」タグで、「Runtime Library」の欄を「Multi-threaded Debug DLL (/MDd)」に変更します。



同じく、「構成プロパティ」→「C++」→「プリプロセッサー」タグで、「Preprocessor Definitions」の欄に「USE_TAGGING」を追加します。



修正事項


ユーザー側のヘッダーファイルで、mp4ff.hのインクルードを避けるための不具合の修正。


「mp4ff.h」の45行目、typedef struct の後に構造体名「_mp4ff_callback_t」を追加します。


/* file callback structure */
typedef struct _mp4ff_callback_t ←構造体名の追加
{
uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
uint32_t (*write)(void *udata, void *buffer, uint32_t length);
uint32_t (*seek)(void *user_data, uint64_t position);
uint32_t (*truncate)(void *user_data);
void *user_data;
} mp4ff_callback_t;



mp4ファイル書き込み時に、「mp4.h」ヘッダーファイルのインクルードすることによって、データ型定義が2重定義エラーになる不具合の修正。

「mp4ff_int_types.h」の10行目から19行目までをコメントアウトして、そのすぐ後の行に以下データ型定義8行を追加します。

#ifndef _MP4FF_INT_TYPES_H_
#define _MP4FF_INT_TYPES_H_

#if defined (_WIN32)

#ifdef __MINGW32__
#include
#endif /* #ifdef __MINGW32__ */

/*typedef signed char int8_t; ←ここからコメントアウト。
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed long int32_t;
typedef unsigned long uint32_t;

typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;*/
←ここまで

typedef __int64 int64_t; ←ここから追加
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int8 int8_t;
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t; ←ここまで

#else

#include

#endif


#endif


カバー画像のバイナリー値が読み込めない不具合の修正。

「mp4ff.h」の119行目のすぐ後に構造体メンバー「uint32_t len;」を追加します。

/* metadata tag structure */
typedef struct
{
char *item;
char *value;
uint32_t len; ←追加する構造体メンバー
} mp4ff_tag_t;

「mp4ffint.h」の154行目のすぐ後に構造体メンバー「uint32_t len;」を追加します。

/* metadata tag structure */
typedef struct
{
char *item;
char *value;
uint32_t len; ←追加する構造体メンバー
} mp4ff_tag_t;


「mp4ffint.h」の288行目、mp4ff_tag_add_field関数のプロトタイプに、引数「int32_t len」を追加します。

/* mp4meta.c */
static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, int32_t len); ←引数を追加


「mp4meta.c」のmp4ff_tag_add_field関数を以下の通り変更します。

40行目「int32_t len」を追加。
53行目をコメントアウトして、そのすぐ後に以下11行追加。
60行目のすぐ後に「tags->tags[tags->count].len = 0;」1行追加。


static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, int32_t len)←引数追加
{
void *backup = (void *)tags->tags;

if (!item || (item && !*item) || !value) return 0;

tags->tags = (mp4ff_tag_t*)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t));
if (!tags->tags)
{
if (backup) free(backup);
return 0;
} else {
tags->tags[tags->count].item = strdup(item);
// tags->tags[tags->count].value = strdup(value); ←コメントアウト
tags->tags[tags->count].len = len; ←ここから追加
if (len >= 0) {
tags->tags[tags->count].value = malloc(len + 1);
if (tags->tags[tags->count].value != NULL) {
memcpy(tags->tags[tags->count].value, value, len);
tags->tags[tags->count].value[len] = 0;
}
}
else {
tags->tags[tags->count].value = strdup(value);
} ←ここまで

if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
{
if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
tags->tags[tags->count].item = NULL;
tags->tags[tags->count].value = NULL;
tags->tags[tags->count].len = 0; ←新たに追加する行
return 0;
}

tags->count++;
return 1;
}
}

同じく「mp4meta.c」のmp4ff_tag_set_field関数の85行目、mp4ff_tag_add_field関数呼び出しに引数「0」を追加します。

static int32_t mp4ff_tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value)
{
unsigned int i;

if (!item || (item && !*item) || !value) return 0;

for (i = 0; i < tags->count; i++)
{
if (!stricmp(tags->tags[i].item, item))
{
free(tags->tags[i].value);
tags->tags[i].value = strdup(value);
return 1;
}
}

return mp4ff_tag_add_field(tags, item, value, 0); ←引数0を追加
}

同じく「mp4meta.c」のmp4ff_parse_tag関数を以下の通り変更します。

229行目に「uint32_t len = 0;」一行追加。
255行目のmp4ff_tag_add_field関数呼び出しに、引数「-1」を追加。
262行目のmp4ff_tag_add_field関数呼び出しに、引数「-1」を追加。
272行目を削除して、「+ (parent_atom_type == ATOM_TRACK ? sizeof(uint16_t) : 0)」の1行を新たに追加。
282行目のコメントアウト行のすぐ後に「if (parent_atom_type == ATOM_TRACK)」の1行を追加。
283行目のコメントアウトを外します。
286行目のmp4ff_tag_add_field関数呼び出しに、引数「-1」を追加。
290行目のmp4ff_tag_add_field関数呼び出しに、引数「-1」を追加。
297行目の直ぐ後「len = (uint32_t)(subsize-(header_size+8));」一行追加。
318行目のmp4ff_tag_add_field関数呼び出しに引数「len」を追加。


static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size)
{
uint8_t atom_type;
uint8_t header_size = 0;
uint64_t subsize, sumsize = 0;
char * name = NULL;
char * data = NULL;
uint32_t done = 0;
uint32_t len = 0; ←新たに追加する行

while (sumsize < size)
{
uint64_t destpos;
subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
destpos = mp4ff_position(f)+subsize-header_size;
if (!done)
{
if (atom_type == ATOM_DATA)
{
mp4ff_read_char(f); /* version */
mp4ff_read_int24(f); /* flags */
mp4ff_read_int32(f); /* reserved */

/* some need special attention */
if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
{
if (subsize - header_size >= 8 + 2)
{
uint16_t val = mp4ff_read_int16(f);

if (parent_atom_type == ATOM_TEMPO)
{
char temp[16];
sprintf(temp, "%.5u BPM", val);
mp4ff_tag_add_field(&(f->tags), "tempo", temp, -1); ←引数-1を追加
}
else
{
const char * temp = mp4ff_meta_index_to_genre(val);
if (temp)
{
mp4ff_tag_add_field(&(f->tags), "genre", temp, -1); ←引数-1を追加
}
}
done = 1;
}
} else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
/* if (!done && subsize - header_size >= 8 + 8) */
/* modified by AJS */

if ( !done && (subsize - header_size) >=
(sizeof(char) + sizeof(uint8_t)*3 + sizeof(uint32_t) + /* version + flags + reserved */
// + sizeof(uint16_t) /* leading uint16_t */ ←削除
+ (parent_atom_type == ATOM_TRACK ? sizeof(uint16_t) : 0) ←新たに追加
+ sizeof(uint16_t) /* track / disc */
+ sizeof(uint16_t)) /* totaltracks / totaldiscs */
)
{
uint16_t index,total;
char temp[32];
mp4ff_read_int16(f);
index = mp4ff_read_int16(f);
total = mp4ff_read_int16(f);
/* modified by AJS */
if (parent_atom_type == ATOM_TRACK) ←新たに追加
mp4ff_read_int16(f); ←コメントアウトを外す

sprintf(temp,"%d",index);
mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc",
temp, -1); ←引数-1を追加
if (total>0)
{
sprintf(temp,"%d",total);
mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs",
temp, -1); ←引数-1を追加
}
done = 1;
}
} else
{
if (data) {free(data);data = NULL;}
data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8)));
len = (uint32_t)(subsize-(header_size+8)); ←新たに追加する行
}
} else if (atom_type == ATOM_NAME) {
if (!done)
{
mp4ff_read_char(f); /* version */
mp4ff_read_int24(f); /* flags */
if (name) free(name);
name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4)));
}
}
mp4ff_set_position(f, destpos);
sumsize += subsize;
}
}

if (data)
{
if (!done)
{
if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name);
if (name) mp4ff_tag_add_field(&(f->tags), name, data, len); ←引数「len」を追加
}

free(data);
}
if (name) free(name);
return 1;
}

同じく「mp4meta.c」の365行目附近に、mp4ff_meta_find_by_name_and_return_len関数を新たに追加します。

static int32_t mp4ff_meta_find_by_name_and_return_len(const mp4ff_t *f, const char *item, char **value)
{
uint32_t i;

for (i = 0; i < f->tags.count; i++)
{
if (!stricmp(f->tags.tags[i].item, item))
{
uint32_t len = f->tags.tags[i].len;
*value = NULL;
*value = malloc(len);
if (*value != NULL) {
memcpy(*value, f->tags.tags[i].value, len);
return len;
}
}
}

*value = NULL;

/* not found */
return 0;
}

同じく「mp4meta.c」のmp4ff_meta_get_coverart関数内、458行目の行をコメントアウトして、そのすぐ後に以下追加します。

int32_t mp4ff_meta_get_coverart(const mp4ff_t *f, char **value)
{
// return mp4ff_meta_find_by_name(f, "cover", value); ←コメントアウト
return mp4ff_meta_find_by_name_and_return_len(f, "cover", value); ←追加
}

最後にビルドしてエラーがなければ成功です。





スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/77-4a698fae
Listed below are links to weblogs that reference
MP4ファイル音声の再生 第1部 from マルチメディアファイルフォーマット

Home > AACファイルフォーマット > MP4ファイル音声の再生 第1部

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る