1/*
2 * Copyright 2010 Stephan A��mus <superstippi@gmx.de>. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "CodecTable.h"
8
9extern "C" {
10	#include "avcodec.h"
11	#include "avformat.h"
12}
13
14//XXX: newer versions have it in libavformat/internal.h
15typedef struct AVCodecTag {
16    enum CodecID id;
17    unsigned int tag;
18} AVCodecTag;
19
20
21struct AVInputFamily gAVInputFamilies[] = {
22	{ B_AIFF_FORMAT_FAMILY, "aiff" },
23	{ B_AVI_FORMAT_FAMILY, "avi" },
24	{ B_MPEG_FORMAT_FAMILY, "mpeg" },
25	{ B_QUICKTIME_FORMAT_FAMILY, "mov" },
26	{ B_ANY_FORMAT_FAMILY, NULL}
27};
28
29static const int32 sMaxFormatCount = 1024;
30media_format gAVCodecFormats[sMaxFormatCount];
31
32
33status_t
34register_avcodec_tags(media_format_family family, const char *avname, int &index)
35{
36	AVInputFormat *inputFormat = av_find_input_format(avname);
37	if (inputFormat == NULL)
38		return B_MEDIA_NO_HANDLER;
39
40	BMediaFormats mediaFormats;
41	if (mediaFormats.InitCheck() != B_OK)
42		return B_ERROR;
43
44	for (int tagSet = 0; inputFormat->codec_tag[tagSet]; tagSet++) {
45		const AVCodecTag *tags = inputFormat->codec_tag[tagSet];
46		if (tags == NULL)
47			continue;
48
49		for (; tags->id != CODEC_ID_NONE; tags++) {
50			// XXX: we might want to keep some strange PCM codecs too...
51			// skip unwanted codec tags
52			if (tags->tag == CODEC_ID_RAWVIDEO
53				|| (tags->tag >= CODEC_ID_PCM_S16LE
54					&& tags->tag < CODEC_ID_ADPCM_IMA_QT)
55				|| tags->tag >= CODEC_ID_DVD_SUBTITLE)
56				continue;
57
58			if (index >= sMaxFormatCount) {
59				fprintf(stderr, "Maximum format count reached for auto-generated "
60					"AVCodec to media_format mapping, but there are still more "
61					"AVCodecs compiled into libavcodec!\n");
62				break;
63			}
64
65			media_format format;
66			// Determine media type
67			if (tags->tag < CODEC_ID_PCM_S16LE)
68				format.type = B_MEDIA_ENCODED_VIDEO;
69			else
70				format.type = B_MEDIA_ENCODED_AUDIO;
71
72			media_format_description description;
73			memset(&description, 0, sizeof(description));
74
75			// Hard-code everything to B_MISC_FORMAT_FAMILY to ease matching
76			// later on.
77			description.family = family;
78			switch (family) {
79				case B_AIFF_FORMAT_FAMILY:
80					description.u.aiff.codec = tags->tag;
81					break;
82				case B_AVI_FORMAT_FAMILY:
83					description.u.avi.codec = tags->tag;
84					break;
85				case B_MPEG_FORMAT_FAMILY:
86					description.u.mpeg.id = tags->tag;
87					break;
88				case B_QUICKTIME_FORMAT_FAMILY:
89					description.u.quicktime.codec = tags->tag;
90					break;
91				case B_WAV_FORMAT_FAMILY:
92					description.u.wav.codec = tags->tag;
93					break;
94				default:
95					break;
96			}
97
98			format.require_flags = 0;
99			format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
100
101			if (mediaFormats.MakeFormatFor(&description, 1, &format) != B_OK)
102				return B_ERROR;
103
104			gAVCodecFormats[index] = format;
105
106			index++;
107		}
108	}
109	return B_OK;
110}
111
112
113status_t
114build_decoder_formats(media_format** _formats, size_t* _count)
115{
116	BMediaFormats mediaFormats;
117	if (mediaFormats.InitCheck() != B_OK)
118		return B_ERROR;
119
120	int32 index = 0;
121	AVCodec* codec = NULL;
122	while ((codec = av_codec_next(codec)) != NULL) {
123		if (index >= sMaxFormatCount) {
124			fprintf(stderr, "Maximum format count reached for auto-generated "
125				"AVCodec to media_format mapping, but there are still more "
126				"AVCodecs compiled into libavcodec!\n");
127			break;
128		}
129		media_format format;
130		// Determine media type
131		switch (codec->type) {
132			case AVMEDIA_TYPE_VIDEO:
133				format.type = B_MEDIA_ENCODED_VIDEO;
134				break;
135			case AVMEDIA_TYPE_AUDIO:
136				format.type = B_MEDIA_ENCODED_AUDIO;
137				break;
138			default:
139				// ignore this AVCodec
140				continue;
141		}
142
143		media_format_description description;
144		memset(&description, 0, sizeof(description));
145
146		// Hard-code everything to B_MISC_FORMAT_FAMILY to ease matching
147		// later on.
148		description.family = B_MISC_FORMAT_FAMILY;
149		description.u.misc.file_format = 'ffmp';
150		description.u.misc.codec = codec->id;
151
152		format.require_flags = 0;
153		format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
154
155		if (mediaFormats.MakeFormatFor(&description, 1, &format) != B_OK)
156			return B_ERROR;
157
158		gAVCodecFormats[index] = format;
159
160		index++;
161	}
162
163	*_formats = gAVCodecFormats;
164	*_count = index;
165
166	return B_OK;
167}
168
169