Fork me on GitHub

第三方网站分享

medium.com

Medium 是一个广受欢迎的在线发布平台,于2012年由Twitter的共同创始人Evan Williams创建。这个平台旨在允许个人作者、思想领袖、记者,以及各种专业人士发表文章,分享见解和故事。Medium试图填补传统博客和新闻网站之间的空白,为用户提供一个既简洁又强大的写作和阅读环境。

主要特点

  • 高质量内容:Medium强调内容的质量和深度,鼓励作者发布有洞察力、有价值的文章。
  • 简洁的设计:该平台以其干净、无干扰的设计著称,专注于增强阅读体验。
  • 多样化的话题:在Medium上,你可以找到从科技、文化、政治到个人发展等各个领域的文章。
  • 互动性:读者可以通过点赞、评论和分享文章来与内容互动,也可以关注喜欢的作者。
  • 算法推荐:Medium使用算法推荐系统,根据用户的阅读习惯和偏好推荐文章。

为作者和读者提供的价值

对于作者来说,Medium提供了一个易于使用的平台,可以轻松发布文章,同时通过内置的受众和分发机制,让他们的作品被更广泛的读者看到。此外,通过Medium的合作伙伴计划,作者还可以通过其文章获得收入。

对于读者来说,Medium是发现新思想、学习新知识和获取不同领域见解的宝贵资源。平台的个性化推荐系统可以帮助读者发现他们感兴趣的内容。

商业模式

Medium采用订阅模式,提供免费内容的同时,也设有会员计划。会员支付月费或年费后,可以无限制访问平台上的所有付费文章,并享受其他额外的会员特权,如更好的阅读体验和早期访问新功能。

总结

Medium是一个结合了高质量写作和阅读体验的平台,适合那些寻求深度内容和想要分享自己见解的人们。无论是想要建立个人品牌、分享专业知识,还是简单地寻找高质量阅读材料,Medium都是一个值得尝试的平台。

juejin.cn

掘金 是一个专注于技术领域的中文社区平台,旨在帮助开发者成长和交流。它汇聚了大量的技术文章、教程和资源,涵盖了编程语言、前端、后端、移动开发、人工智能、云计算等多个技术领域。掘金为开发者提供了一个分享知识、学习技能和与同行交流的环境。

主要特点

  • 丰富的技术内容:掘金上有大量由用户生成的技术文章和教程,覆盖了软件开发的几乎所有方面。内容更新频繁,信息量大。
  • 社区交流:掘金鼓励用户之间的互动,包括评论、点赞、收藏和分享。这不仅增加了内容的互动性,也促进了知识的传播和交流。
  • 专栏和项目:除了常规的文章和帖子,掘金还允许用户创建专栏,发布更为系统和深入的内容。用户也可以分享自己的项目和开源作品。
  • 技术活动和挑战:掘金定期举办技术活动和编程挑战,鼓励用户参与,提高技能,同时有机会获得奖品和认可。
  • 个性化推荐:掘金通过分析用户的阅读偏好和互动行为,推荐相关的内容,帮助用户发现他们可能感兴趣的新知识。

为开发者提供的价值

  • 知识共享:开发者可以通过撰写和分享文章来展示自己的专业知识,建立个人品牌。
  • 学习成长:通过阅读高质量的技术文章和参与社区讨论,开发者可以快速提高自己的技术水平。
  • 资源获取:掘金社区中包含了大量的编程资源和工具,开发者可以方便地找到解决问题的工具和方法。
  • 建立连接:掘金为开发者提供了一个交流平台,可以与同行建立联系,拓展职业网络。

总结

掘金是一个集技术文章分享、社区交流、资源获取于一体的技术社区平台,特别适合软件开发者和技术爱好者。在这里,用户不仅可以获取到最新的技术信息和学习资源,还可以参与讨论和交流,与其他开发者共同成长。

从 RESTful API 开始说起

RESTful API

RESTful API是一种软件架构风格或设计模式,用于构建网络应用程序的接口。REST(Representational State Transfer,表述性状态转移)由Roy Fielding在他的博士论文中提出,是一组架构原则,指导如何设计网络上的分布式系统。RESTful API利用HTTP协议的方法来组织和处理网络请求,使得Web服务可以以标准化的方式进行交互。

核心原则

RESTful API设计遵循几个核心原则,确保系统简洁、高效、易于使用和维护:

  • 无状态(Stateless):每个请求从客户端到服务器必须包含所有必要的信息来理解和处理请求。服务器不会存储任何客户端请求之间的状态信息,这使得每个请求都是独立的。
  • 客户端-服务器(Client-Server):客户端和服务器之间的交互应该是松耦合的,即客户端不需要知道服务器端的操作细节,服务器端也不需要知道客户端的界面布局。
  • 统一接口(Uniform Interface):确定了客户端与服务器交互的一组约定,简化和解耦了架构,使得每部分可以独立地演进。其中包括使用标准的HTTP方法(GET、POST、PUT、DELETE等)。
  • 可缓存(Cacheable):响应数据标记为可缓存或不可缓存。如果是可缓存的,客户端就可以重用响应数据,提高应用性能。
  • 分层系统(Layered System):客户端不能直接与后端服务器交互,可能会通过中间层来提高系统的可扩展性、安全性等。

HTTP方法

RESTful API通常使用以下HTTP方法来对资源进行操作:

  • GET:从服务器检索特定资源或资源列表。
  • POST:在服务器上创建一个新的资源。
  • PUT:更新服务器上的资源,提供完整的资源信息。
  • DELETE:从服务器删除特定资源。
  • PATCH:对服务器上的资源进行部分更新。

资源表示

在RESTful API中,”资源”是一个关键概念,它是通过URI(统一资源标识符)来标识的。资源的具体信息通常以JSON或XML格式的数据来表示,这样可以简化客户端和服务器之间的数据交换。

使用场景

RESTful API适用于任何客户端与服务器之间的交互场景,特别是在开发Web服务和公开的API时。由于其使用简单、灵活性高、易于理解和实现,RESTful API已成为当前网络应用中数据交换的主要标准之一。

总结

RESTful API通过使用Web的现有标准和协议(特别是HTTP),提供了一种高效、可靠且可扩展的方式来构建和使用Web服务。遵循REST原则的API易于被广泛的客户端(包括浏览器、移动应用和服务器端应用)使用,促进了不同平台和技术之间的互操作性。

从零开始写一个 Android 播放器(一)

Mp4Extractor 解析 mp4 数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.Mp4Extractor;
import androidx.media3.extractor.TrackOutput;
import androidx.media3.common.util.Util;

import java.io.IOException;
import java.io.InputStream;

public class MediaExtractorExample {

/**
* 解析 MP4 文件
*
* @param inputStream 输入流
* @throws IOException 如果读取文件时发生错误
*/
public void extractMp4(InputStream inputStream) throws IOException {
// 创建一个 ExtractorInput 实现,用于从输入流中读取数据
ExtractorInput extractorInput = new ExtractorInput() {
private InputStream input = inputStream;

@Override
public long getLength() throws IOException {
return input.available(); // 获取文件长度
}

@Override
public long getPosition() throws IOException {
return 0; // 返回当前读取的位置,假设从头开始读取
}

@Override
public void advancePeekPosition(int length) throws IOException {
input.skip(length); // 跳过指定长度的字节
}

@Override
public void resetPeekPosition() throws IOException {
// 重置读取位置,这里未实现
}

@Override
public int read(byte[] target, int offset, int length) throws IOException {
return input.read(target, offset, length); // 从输入流中读取数据到目标字节数组
}

@Override
public void close() throws IOException {
input.close(); // 关闭输入流
}
};

// 创建 MP4 提取器
Mp4Extractor mp4Extractor = new Mp4Extractor();

// 提供输出轨道的处理器,简单打印数据
TrackOutput trackOutput = new TrackOutput() {
@Override
public void format(Format format) {
// 处理格式信息
System.out.println("Format: " + format);
}

@Override
public void sampleData(ExtractorInput input, int length) throws IOException {
// 处理样本数据
byte[] buffer = new byte[length];
input.readFully(buffer, 0, length); // 读取样本数据
System.out.println("Sample Data: " + new String(buffer));
}

@Override
public void sampleMetadata(long timeUs, int flags, int size, int offset, CryptoData cryptoData) {
// 处理样本元数据
System.out.println("Sample Metadata: timeUs=" + timeUs + ", flags=" + flags);
}
};

// 使用提取器初始化 ExtractorOutput
mp4Extractor.init(new ExtractorOutput() {
@Override
public void seekMap(SeekMap seekMap) {
// 处理 SeekMap
long duration = seekMap.getDurationUs();
System.out.println("Media Duration: " + duration);
}

@Override
public void track(int id, TrackOutput trackOutput) {
// 添加轨道
System.out.println("Track: " + id);
}
});

// 解析文件数据
mp4Extractor.read(extractorInput, new PositionHolder(), 0);
}
}

Mp4Extractor 需要的 API 名称以及对应的功能


构造方法

  1. Mp4Extractor()
    • 功能: 默认构造函数,初始化 Mp4Extractor 对象。
  2. Mp4Extractor(Factory factory)
    • 功能: 通过工厂方法创建 Mp4Extractor 实例,用于支持动态依赖注入。
  3. Mp4Extractor(int flags)
    • 功能: 通过标志(flags)初始化解析器,例如控制是否解析特定类型的 Atom。

工厂方法

  1. newFactory(Factory factory): ExtractorsFactory
    • 功能: 提供用于创建 Mp4Extractor 实例的工厂方法。

格式验证

  1. sniff(ExtractorInput input): boolean
    • 功能: 检测输入流是否是支持的 MP4 文件格式。
  2. getSniffFailureDetails(): ImmutableList<SniffFailure>
    • 功能: 如果 sniff 方法失败,返回失败的详细信息。

初始化与资源管理

  1. init(ExtractorOutput output): void
    • 功能: 初始化解析器,设置音视频数据的输出接口。
  2. release(): void
    • 功能: 释放资源,清理解析器的内部状态。

文件解析

  1. read(ExtractorInput input, PositionHolder seekPosition): int
    • 功能: 读取输入流,逐步解析 MP4 文件的音视频数据或元数据。
  2. seek(long position, long timeUs): void
    • 功能: 跳转到指定的文件位置和时间戳。
  3. getDurationUs(): long
    • 功能: 返回 MP4 文件的总时长(单位:微秒)。

跳转与定位

  1. getSeekPoints(long timeUs): SeekPoints
    • 功能: 根据时间戳获取跳转点,帮助实现精确跳转。
  2. isSeekable(): boolean
    • 功能: 判断当前 MP4 文件是否支持跳转功能。

Atom 解析

  1. shouldParseLeafAtom(int atomType): boolean
    • 功能: 判断是否需要解析叶子 Atom(无子元素的 Atom)。
  2. shouldParseContainerAtom(int atomType): boolean
    • 功能: 判断是否需要解析容器 Atom(包含子元素的 Atom)。
  3. readAtomHeader(ExtractorInput input): boolean
    • 功能: 读取当前 Atom 的头部信息(类型和大小)。
  4. readAtomPayload(ExtractorInput input, PositionHolder positionHolder): boolean
    • 功能: 读取 Atom 的有效负载部分。
  5. processMoovAtom(ContainerAtom moov): void
    • 功能: 处理 MP4 文件中的 moov Atom,它包含元数据和轨道信息。
  6. processUnparsedAtom(long atomSize): void
    • 功能: 跳过未解析的 Atom,通常用于忽略无关数据。
  7. brandToFileType(int brand): int
    • 功能:ftyp Atom 中的 Major Brand 转换为文件类型标识。
  8. processAtomEnded(long atomSize): void
    • 功能: 在解析完整个 Atom 后执行收尾处理。

音视频样本处理

  1. readSample(ExtractorInput input, PositionHolder positionHolder): int
    • 功能: 读取音视频样本数据(如一帧音频或视频)。
  2. getTrackIndexOfNextReadSample(long timeUs): int
    • 功能: 获取下一帧需要读取的轨道索引。
  3. updateSampleIndex(Mp4Track track, long timeUs): void
    • 功能: 更新轨道的样本索引,用于定位到特定的时间点。
  4. calculateAccumulatedSampleSizes(Mp4Track[] tracks): long[][]
    • 功能: 计算所有轨道中样本的累积大小,用于样本偏移计算。
  5. getSynchronizationSampleIndex(TrackSampleTable sampleTable, long timeUs): long
    • 功能: 获取同步样本索引(关键帧),用于跳转或快速预览。
  6. maybeAdjustSeekOffset(TrackSampleTable sampleTable, long timeUs, long seekPosition): long
    • 功能: 根据当前轨道信息调整跳转偏移。
  7. processEndOfStreamReadingAtomHeader(): void
    • 功能: 在文件流结束时,处理 Atom 头部的读取操作。

辅助方法

  1. maybeSkipRemainingMetaAtomHeaderBytes(ExtractorInput input): void
    • 功能: 跳过当前 Atom 的剩余头部字节,通常用于优化解析流程。