Compare commits
144
Commits
f56c43d82b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d73a1dda56 | ||
|
|
2177452f52 | ||
|
|
b526fe4670 | ||
|
|
1f696902da | ||
|
|
14e26702c1 | ||
|
|
ad505863b7 | ||
|
|
24a2a74768 | ||
|
|
278c1b4510 | ||
|
|
dab91b1a65 | ||
|
|
0400385cf8 | ||
|
|
378f6495be | ||
|
|
257ddb6776 | ||
|
|
c5d0a827e9 | ||
|
|
b64df76c90 | ||
|
|
ac1c0b12b3 | ||
|
|
fd0ee96c04 | ||
|
|
c8000d022c | ||
|
|
5b86fc7e2b | ||
|
|
6813a6bdd7 | ||
|
|
5ded732345 | ||
|
|
fa5e6bbedc | ||
|
|
d0422fafeb | ||
|
|
2327326cca | ||
|
|
162d2b7563 | ||
|
|
964655af7f | ||
|
|
0405629106 | ||
|
|
f9e8c3de37 | ||
|
|
1da8d5bb62 | ||
|
|
5e7c121cf8 | ||
|
|
274eaa3213 | ||
|
|
80c06c5ab3 | ||
|
|
d7647f57e8 | ||
|
|
ba869e8eb4 | ||
|
|
8c3bc96417 | ||
|
|
dc19ff5339 | ||
|
|
e9e585bad0 | ||
|
|
9526104a4a | ||
|
|
92d228d2e0 | ||
|
|
5a8e2293ca | ||
|
|
2ed5957365 | ||
|
|
86f387b2fa | ||
|
|
57039939fd | ||
|
|
416279a11f | ||
|
|
10fddc35d3 | ||
|
|
e056e68808 | ||
|
|
a5c0bd67a8 | ||
|
|
a7df635f66 | ||
|
|
99e1d49a4b | ||
|
|
cca0d282d6 | ||
|
|
cd8deba1f9 | ||
|
|
b0dbaa50df | ||
|
|
466a819800 | ||
|
|
68c16339ea | ||
|
|
112012ce0c | ||
|
|
9aee32e42d | ||
|
|
a8c7641e69 | ||
|
|
996a75fc3e | ||
|
|
3f0a7d0d5c | ||
|
|
406e7820bc | ||
|
|
d4ec1d5652 | ||
|
|
1383781dc6 | ||
|
|
a9fdf9ac9f | ||
|
|
a72b1778a9 | ||
|
|
be016409d7 | ||
|
|
3fefb5476f | ||
|
|
1ba808fcf0 | ||
|
|
70869d7e1e | ||
|
|
83546e5e10 | ||
|
|
614e244be7 | ||
|
|
b73fbf2160 | ||
|
|
33a4674a82 | ||
|
|
5052d5cf52 | ||
|
|
768dd0ebf0 | ||
|
|
c80e173ad9 | ||
|
|
764025f1e7 | ||
|
|
98d4d3e463 | ||
|
|
4f389dea45 | ||
|
|
12c135dc95 | ||
|
|
cfe4686cef | ||
|
|
9f6c424e04 | ||
|
|
16640559b3 | ||
|
|
e61fa99c98 | ||
|
|
5425589ad9 | ||
|
|
175165184d | ||
|
|
df69d779d9 | ||
|
|
6e7e9685ab | ||
|
|
f21f96f8a3 | ||
|
|
98fd382ed4 | ||
|
|
62f1e646ab | ||
|
|
dc6b95108f | ||
|
|
578f3f96ad | ||
|
|
773796d36a | ||
|
|
401387bd00 | ||
|
|
e9b287cf81 | ||
|
|
197d704e27 | ||
|
|
a4e21be0ec | ||
|
|
f794e24f24 | ||
|
|
5670ece56d | ||
|
|
c90b660429 | ||
|
|
ca3527bc17 | ||
|
|
37a6497c84 | ||
|
|
b5bbf299bd | ||
|
|
520350f9d1 | ||
|
|
32e38fda59 | ||
|
|
03086981e5 | ||
|
|
167c433a59 | ||
|
|
af80e71d17 | ||
|
|
9dd1276aa1 | ||
|
|
6404f4176e | ||
|
|
6e64d739ac | ||
|
|
a13f66d917 | ||
|
|
57961d84de | ||
|
|
87fa624983 | ||
|
|
1e06d82015 | ||
|
|
e646a72418 | ||
|
|
6c4d7e68f6 | ||
|
|
fd0d61c584 | ||
|
|
a11e40c56c | ||
|
|
4acc01b742 | ||
|
|
53ba35a3de | ||
|
|
634d703572 | ||
|
|
2f63f8550a | ||
|
|
f7f71ca195 | ||
|
|
b34750099e | ||
|
|
44ac92ca17 | ||
|
|
5c7325843c | ||
|
|
c2e4e01036 | ||
|
|
ed8b691452 | ||
|
|
068a7bd8e2 | ||
|
|
8f3dc93ec1 | ||
|
|
012fcd7b9b | ||
|
|
69d93778a4 | ||
|
|
d1f080ded1 | ||
|
|
1272c91430 | ||
|
|
2a25b49baa | ||
|
|
428b16cda2 | ||
|
|
a9cef3b40e | ||
|
|
867ee66499 | ||
|
|
ee7cee7638 | ||
|
|
e979b78fb5 | ||
|
|
5a6dad2f24 | ||
|
|
dc69070823 | ||
|
|
193946cadf | ||
|
|
668d33543c |
+150
-21
@@ -9,7 +9,7 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "bums.lunatic.launcher"
|
||||
namespace = "bums.lunatic.launcher"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
@@ -18,8 +18,22 @@ android {
|
||||
versionCode = 38
|
||||
versionName = "2.8.2"
|
||||
multiDexEnabled = true
|
||||
ndk {
|
||||
abiFilters += listOf("arm64-v8a") // 필요한 ABI만 빌드하도록 필터링
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags += "-std=c++17"
|
||||
arguments += "-DANDROID_STL=c++_shared"
|
||||
}
|
||||
}
|
||||
// 이 부분을 추가하여 prefab 기능을 활성화합니다.
|
||||
buildFeatures {
|
||||
prefab = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
buildTypes {
|
||||
getByName("debug") {
|
||||
isMinifyEnabled = false
|
||||
@@ -27,19 +41,24 @@ android {
|
||||
isDebuggable = true
|
||||
// applicationIdSuffix = ".debug"
|
||||
// versionNameSuffix = "-debug"
|
||||
buildConfigField("Long","BuildDateTime", getDateTime().toString().plus("L"))
|
||||
buildConfigField("Long","BuildDateTime", "${getDateTime()}L")
|
||||
resValue ("string", "app_name", "Bums Launcher Debug")
|
||||
}
|
||||
|
||||
getByName("release") {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
buildConfigField("Long","BuildDateTime", getDateTime().toString().plus("L"))
|
||||
buildConfigField("Long","BuildDateTime", "${getDateTime()}L")
|
||||
proguardFiles (getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
resValue ("string", "app_name", "Bums Launcher")
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path = file("src/main/cpp/CMakeLists.txt")
|
||||
version = "3.22.1"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
||||
getByName("debug") {
|
||||
@@ -50,6 +69,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
sourceSets["main"].jniLibs.srcDirs("src/main/jniLibs")
|
||||
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
if (buildType.name == "release") {
|
||||
@@ -73,51 +96,113 @@ android {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
packagingOptions.resources.excludes.add("META-INF/*")
|
||||
packagingOptions.resources.excludes.add("mozilla/*")
|
||||
packagingOptions.resources.excludes.add("META-INF/*/*")
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
ndkVersion = "29.0.13846066 rc3"
|
||||
// buildToolsVersion = "35.0.1"
|
||||
packaging {
|
||||
doNotStrip("**/libaria2c.zip.so")
|
||||
doNotStrip("**/libffmpeg.zip.so")
|
||||
doNotStrip("**/libpython.zip.so")
|
||||
jniLibs {
|
||||
pickFirsts.add("lib/**/libc++_shared.so")
|
||||
pickFirsts.add("lib/**/libavcodec.so")
|
||||
pickFirsts.add("lib/**/libavfilter.so")
|
||||
pickFirsts.add("lib/**/libavformat.so")
|
||||
pickFirsts.add("lib/**/libavutil.so")
|
||||
pickFirsts.add("lib/**/libswresample.so")
|
||||
pickFirsts.add("lib/**/libswscale.so")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(fileTree(mapOf(
|
||||
"dir" to "libs",
|
||||
"include" to listOf("*.aar", "*.jar"),
|
||||
)))
|
||||
implementation(project(":gdrive"))
|
||||
implementation("com.google.android.gms:play-services-wearable:19.0.0")
|
||||
val kotlinVersion: String? by extra
|
||||
implementation ("androidx.appcompat:appcompat:1.7.0")
|
||||
val realmVersion = "2.0.0"
|
||||
implementation ("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation ("androidx.biometric:biometric-ktx:1.2.0-alpha05")
|
||||
implementation ("androidx.browser:browser:1.8.0")
|
||||
implementation ("androidx.core:core-ktx:1.15.0")
|
||||
implementation ("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
|
||||
implementation ("com.google.android.material:material:1.12.0")
|
||||
implementation ("com.ibm.icu:icu4j:68.1")
|
||||
implementation (kotlin("stdlib", version = kotlinVersion))
|
||||
implementation ("com.ibm.icu:icu4j:77.1")
|
||||
implementation (kotlin("stdlib", version = "2.0.10"))
|
||||
implementation ("com.github.cachapa:ExpandableLayout:2.9.2")
|
||||
implementation ("com.squareup.picasso:picasso:2.71828")
|
||||
|
||||
implementation ("androidx.work:work-runtime:2.10.0")
|
||||
implementation ("com.google.code.gson:gson:2.11.0")
|
||||
implementation ("io.realm.kotlin:library-base:2.1.0")
|
||||
implementation ("org.jsoup:jsoup:1.18.1")
|
||||
implementation ("org.apache.commons:commons-text:1.12.0")
|
||||
implementation ("com.google.code.gson:gson:2.13.1")
|
||||
implementation ("io.realm.kotlin:library-base:${realmVersion}")
|
||||
implementation ("org.jsoup:jsoup:1.21.2")
|
||||
implementation ("org.apache.commons:commons-text:1.14.0")
|
||||
implementation("com.squareup.okhttp:okhttp:2.7.5")
|
||||
implementation("com.google.android.gms:play-services-location:21.3.0")
|
||||
implementation("com.google.android.gms:play-services-tasks:18.2.0")
|
||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
implementation("com.squareup.retrofit2:converter-scalars:2.6.4")
|
||||
implementation("com.google.android.gms:play-services-tasks:18.3.2")
|
||||
implementation("com.squareup.retrofit2:retrofit:3.0.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:3.0.0")
|
||||
implementation("com.squareup.retrofit2:converter-scalars:3.0.0")
|
||||
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
||||
implementation("com.squareup.picasso:picasso:2.71828")
|
||||
implementation("com.github.delight-im:Android-AdvancedWebView:v3.2.1")
|
||||
implementation(project(":library"))
|
||||
implementation(project(":utils"))
|
||||
// implementation(project(":library"))
|
||||
// implementation(project(":utils"))
|
||||
implementation( "com.github.bumptech.glide:glide:4.11.0")
|
||||
// implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
||||
implementation ("com.github.bumptech.glide:okhttp3-integration:4.11.0")
|
||||
implementation ("com.github.chrisbanes:PhotoView:2.3.0")
|
||||
implementation ("androidx.exifinterface:exifinterface:1.3.6")
|
||||
|
||||
// https://mvnrepository.com/artifact/org.mozilla.geckoview/geckoview
|
||||
implementation("org.mozilla.geckoview:geckoview:139.0.20250523173407")
|
||||
|
||||
|
||||
implementation("com.vladsch.flexmark:flexmark-all:0.64.8")
|
||||
// implementation 'com.vladsch.flexmark:flexmark-all:0.64.8'
|
||||
// implementation("org.opencv:opencv-android:4.11.0")
|
||||
// build.gradle에 추가
|
||||
implementation ("androidx.emoji2:emoji2:1.4.0")
|
||||
implementation ("com.googlecode.juniversalchardet:juniversalchardet:1.0.3")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
|
||||
// implementation ("com.github.aeonSolutions:FloatingActionButtonMenuDrag:1.1")
|
||||
implementation("io.github.junkfood02.youtubedl-android:library:0.17.4")
|
||||
implementation("io.github.junkfood02.youtubedl-android:ffmpeg:0.17.4")
|
||||
implementation("io.github.junkfood02.youtubedl-android:aria2c:0.17.4")
|
||||
implementation("io.coil-kt:coil:2.5.0")
|
||||
implementation("io.coil-kt:coil-gif:2.5.0")
|
||||
implementation ("com.squareup.okhttp3:logging-interceptor:4.11.0")
|
||||
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
|
||||
|
||||
// Fragment KTX: Fragment에서 by viewModels() 델리게이트를 사용하기 위해 필수
|
||||
implementation("androidx.fragment:fragment-ktx:1.8.1")
|
||||
|
||||
// Lifecycle KTX: viewLifecycleOwner.lifecycleScope 등을 사용하기 위해 필요
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")
|
||||
|
||||
|
||||
|
||||
// implementation ("com.arthenica:ffmpeg-kit-full:4.5.LTS")
|
||||
// implementation ("com.arthenica:ffmpeg-kit-full:6.0-2")
|
||||
|
||||
// implementation(files("libs/ffmpeg-kit-full-6.0-2.LTS.aar"))
|
||||
// implementation("com.arthenica:ffmpeg-kit-full-gpl:5.1")
|
||||
|
||||
|
||||
implementation ("androidx.media:media:1.7.0")
|
||||
@@ -126,5 +211,49 @@ dependencies {
|
||||
// implementation ("me.everything:providers-core:1.0.1")
|
||||
// implementation ("androidx.window:window:1.0.0")
|
||||
// implementation("io.github.vaneproject:hanguleditor:1.0.0")
|
||||
|
||||
|
||||
// implementation ("androidx.concurrent:concurrent-listenablefuture-ktx:1.1.0")
|
||||
implementation ("com.google.guava:guava:33.2.1-jre")
|
||||
val camerax_version = "1.3.0" // 안정적인 최신 버전 사용
|
||||
|
||||
// CameraX 코어 라이브러리
|
||||
implementation("androidx.camera:camera-core:$camerax_version")
|
||||
implementation("androidx.camera:camera-camera2:$camerax_version")
|
||||
|
||||
// CameraX Lifecycle 라이브러리 (Fragment/Activity 생명주기 연결)
|
||||
implementation("androidx.camera:camera-lifecycle:$camerax_version")
|
||||
|
||||
// CameraX View 라이브러리 (PreviewView 등 UI 구성 요소)
|
||||
implementation("androidx.camera:camera-view:$camerax_version")
|
||||
|
||||
// (선택) CameraX 비디오 라이브러리
|
||||
implementation("androidx.camera:camera-video:$camerax_version")
|
||||
|
||||
// (선택) CameraX 확장 라이브러리 (보케, HDR 등)
|
||||
implementation("androidx.camera:camera-extensions:$camerax_version")
|
||||
|
||||
implementation("com.google.mlkit:translate:17.0.3") // 버전 살짝 업그레이드 권장
|
||||
implementation("com.google.mlkit:language-id:17.0.5")
|
||||
implementation("com.google.android.gms:play-services-base:18.5.0")
|
||||
implementation("com.google.mlkit:common:18.11.0")
|
||||
|
||||
constraints {
|
||||
// ⚠️ 이 버전을 프로젝트 루트의 build.gradle.kts에 정의된 kotlinVersion 값과 정확히 일치시키세요.
|
||||
val targetKotlinVersion = "2.0.20"
|
||||
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib") {
|
||||
version { strictly(targetKotlinVersion) }
|
||||
// reason = "Align all Kotlin stdlib versions with the compiler plugin version"
|
||||
}
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") {
|
||||
version { strictly(targetKotlinVersion) }
|
||||
// reason = "Align all Kotlin stdlib versions with the compiler plugin version"
|
||||
}
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-common") {
|
||||
version { strictly(targetKotlinVersion) }
|
||||
// reason = "Align all Kotlin stdlib versions with the compiler plugin version"
|
||||
}
|
||||
}
|
||||
}
|
||||
fun getDateTime() = SimpleDateFormat("yyyyMMddHHmm").format(Date()).toLong()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+176
-160
@@ -23,7 +23,6 @@
|
||||
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
|
||||
<!-- api 33+ -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
|
||||
@@ -46,6 +45,7 @@
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_SMS"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
@@ -54,12 +54,22 @@
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
|
||||
|
||||
<queries>
|
||||
<package android:name="com.google.android.gms" />
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".LunaticLauncher"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
@@ -71,143 +81,184 @@
|
||||
android:stateNotNeeded="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:largeHeap="true"
|
||||
android:debuggable="false"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:hardwareAccelerated="true"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:screenOrientation="nosensor"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
>
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- portrait|reversePortrait|userPortrait|sensorPortrait-->
|
||||
tools:ignore="HardcodedDebugMode">
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".LauncherActivity"
|
||||
android:theme="@style/Theme.LunarLauncher.Starting"
|
||||
android:name=".home.NeoRssActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:launchMode="singleInstance"
|
||||
android:screenOrientation="userPortrait"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection|navigation"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
android:exported="false">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.WEB_SEARCH"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".home.TranslatorActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name=".player.PlayerActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:launchMode="singleInstance"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:screenOrientation="sensor"
|
||||
android:hardwareAccelerated="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
<activity android:name=".home.WebReaderActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:roundIcon="@drawable/ic_launcher"
|
||||
android:label="리더"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density|fontScale|keyboardHidden|keyboard|layoutDirection|navigation"
|
||||
android:screenOrientation="portrait"
|
||||
android:excludeFromRecents="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:taskAffinity="bums.lunatic.launcher.home.WebReaderActivity"
|
||||
android:launchMode="singleTask"> <intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".player.DocumentViewerActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:launchMode="singleInstance"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density|fontScale|keyboardHidden|keyboard|layoutDirection|navigation"
|
||||
android:screenOrientation="portrait"
|
||||
android:excludeFromRecents="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".player.ImageViewerActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:launchMode="singleInstance"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
|
||||
android:screenOrientation="sensor"
|
||||
android:excludeFromRecents="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".LauncherActivity"
|
||||
android:theme="@style/Theme.LunarLauncher.Starting"
|
||||
android:launchMode="singleInstance"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:screenOrientation="userPortrait"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|screenLayout|layoutDirection|navigation"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" /> </intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- <activity-->
|
||||
<!-- android:name=".apps.AppDrawer"-->
|
||||
<!-- android:label="@string/lunar_settings"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </activity>-->
|
||||
<receiver android:name=".receiver.CallReceiver" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PHONE_STATE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".receiver.SmsReceiver"
|
||||
android:exported="true"> <intent-filter android:priority="2147483647">
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
|
||||
|
||||
<!-- <activity-->
|
||||
<!-- android:name=".tokiz.Settings"-->
|
||||
<!-- android:label="@string/lunar_settings"-->
|
||||
<!-- android:launchMode="singleInstance"-->
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- android:exported="true">-->
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- </activity>-->
|
||||
<!-- <activity-->
|
||||
<!-- android:name=".settings.SettingsActivity"-->
|
||||
<!-- android:label="@string/lunar_settings"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </activity>-->
|
||||
<!-- <activity-->
|
||||
<!-- android:name=".behavior.Behavior"-->
|
||||
<!-- android:label="@string/lunar_settings"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.APPLICATION_PREFERENCES" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </activity>-->
|
||||
|
||||
<!-- <receiver android:name=".helpers.HeadsetActionButtonReceiver"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:exported="true" >-->
|
||||
<!-- <intent-filter-->
|
||||
<!-- android:priority="2147483647">-->
|
||||
<!-- <action android:name="android.intent.action.MEDIA_BUTTON"/>-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
|
||||
<!-- <service android:name=".MediaButtonService"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.MEDIA_BUTTON" />-->
|
||||
<!-- <action android:name="android.media.browse.MediaBrowserService" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </service>-->
|
||||
|
||||
<service
|
||||
android:name=".feeds.rss.RssService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="false"/>
|
||||
android:name=".helpers.ForeGroundService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- <service-->
|
||||
<!-- android:name=".helpers.LockService"-->
|
||||
<!-- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"-->
|
||||
<!-- android:exported="false">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.accessibilityservice.AccessibilityService" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="android.accessibilityservice"-->
|
||||
<!-- android:resource="@xml/lock_service" />-->
|
||||
<!-- </service>-->
|
||||
<service
|
||||
android:name=".workers.WatchGestureService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- <receiver-->
|
||||
<!-- android:name=".helpers.AdminReceiver"-->
|
||||
<!-- android:label="@string/app_name"-->
|
||||
<!-- android:description="@string/device_admin_description"-->
|
||||
<!-- android:permission="android.permission.BIND_DEVICE_ADMIN"-->
|
||||
<!-- android:exported="false">-->
|
||||
<!-- <meta-data-->
|
||||
<!-- android:name="android.app.device_admin"-->
|
||||
<!-- android:resource="@xml/device_admin" />-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<service
|
||||
android:name=".workers.TorrentService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- <activity-->
|
||||
<!-- android:name=".home.RssViewerActivity"-->
|
||||
<!-- android:configChanges="keyboardHidden|orientation|screenSize"-->
|
||||
<!-- android:hardwareAccelerated="true"-->
|
||||
<!-- android:launchMode="singleTask"-->
|
||||
<!-- android:exported="true"-->
|
||||
<!-- android:excludeFromRecents="true"-->
|
||||
<!-- android:theme="@style/FinestWebViewTheme.Fullscreen" >-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.VIEW" />-->
|
||||
<!-- <category android:name="android.intent.category.DEFAULT" />-->
|
||||
<!-- <data android:scheme="file"/>-->
|
||||
<!-- <data android:scheme="content"/>-->
|
||||
<!-- <data android:mimeType="text/html"/>-->
|
||||
<!-- <data android:mimeType="text/plain"/>-->
|
||||
<!-- <data android:mimeType="text/xml"/>-->
|
||||
<!-- <data android:mimeType="application/xhtml+xml"/>-->
|
||||
<!-- <data android:mimeType="application/vnd.wap.xhtml+xml"/>-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </activity>-->
|
||||
<service
|
||||
android:name=".wall.MyWallpaperService"
|
||||
android:label="Bums Live Wallpaper"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.wallpaper.WallpaperService" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/wallpaper" />
|
||||
</service>
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".home.tokiz.Settings"
|
||||
android:label="@string/lunar_settings"
|
||||
android:launchMode="singleInstance"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true">
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:label="@string/lunar_settings"
|
||||
android:launchMode="singleTask"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- <service-->
|
||||
<!-- android:name=".feeds.rss.RssService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE"-->
|
||||
<!-- android:exported="false"/>-->
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
@@ -219,55 +270,20 @@
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
<!-- <service android:name=".receiver.NLService"-->
|
||||
<!-- android:label="@string/app_name"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:exported="true"-->
|
||||
<!-- android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.service.notification.NotificationListenerService" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </service>-->
|
||||
<!-- <service android:name="bums.lunatic.launcher.workers.LocationUpdateService" />-->
|
||||
|
||||
<!-- <receiver android:name=".LauncherActivity$EndCallReceiver"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:exported="true">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.PHONE_STATE" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<!-- <receiver android:name=".LauncherActivity$SMSReceiver"-->
|
||||
<!-- android:exported="true"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:permission="android.permission.BROADCAST_SMS">-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.provider.Telephony.SMS_RECEIVED" />-->
|
||||
<!-- <action android:name="android.provider.Telephony.MMS_RECEIVED" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<service android:name=".receiver.NLService"
|
||||
android:label="@string/app_name"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- <receiver-->
|
||||
<!-- android:exported="true"-->
|
||||
<!-- android:enabled="true"-->
|
||||
<!-- android:name=".receiver.PackageEventReceiver"-->
|
||||
<!-- >-->
|
||||
<!-- <intent-filter>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_REPLACED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_INSTALL"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_ADDED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_CHANGED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_FIRST_LAUNCH"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_INSTALL"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_REMOVED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_REPLACED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"/>-->
|
||||
<!-- <action android:name="android.intent.action.PACKAGE_VERIFIED"/>-->
|
||||
<!-- <data android:scheme="package" />-->
|
||||
<!-- </intent-filter>-->
|
||||
<!-- </receiver>-->
|
||||
<service android:name="bums.lunatic.launcher.workers.LocationUpdateService" />
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="ocr,langid,translate" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,152 @@
|
||||
// 페이지 로딩 완료 후 실행
|
||||
window.addEventListener('load', async () => {
|
||||
// 1. URL 패턴 확인
|
||||
const match = window.location.pathname.match(/\/novel\/(\d+)\/(\d+)/);
|
||||
if (!match) return;
|
||||
|
||||
const bookId = match[1];
|
||||
const chapterId = match[2];
|
||||
console.log(`웹소설 스크래퍼: 책 ID [${bookId}] 감지됨.`);
|
||||
|
||||
// ⏳ 2. 1~2초 동안 '페이지 다운(80%)' 스크롤 실행
|
||||
const initialScrollTime = Math.floor(Math.random() * (10000 - 1000 + 1)) + 8000;
|
||||
console.log(`${(initialScrollTime / 1000).toFixed(1)}초 동안 큼직하게 훑어보며 대기합니다... 👀`);
|
||||
await pageSkimScroll(initialScrollTime);
|
||||
|
||||
// 3. 데이터 스크래핑
|
||||
const scrapedData = scrapePage();
|
||||
if (!scrapedData) return;
|
||||
|
||||
// 4. 책 ID별 Storage 저장
|
||||
chrome.storage.local.get(['scrapedBooks'], async (result) => {
|
||||
let scrapedBooks = result.scrapedBooks || {};
|
||||
|
||||
if (!scrapedBooks[bookId]) {
|
||||
scrapedBooks[bookId] = {
|
||||
id: 'book_' + bookId,
|
||||
fileName: scrapedData.novelTitle,
|
||||
chapters: []
|
||||
};
|
||||
}
|
||||
|
||||
let bookData = scrapedBooks[bookId];
|
||||
|
||||
if (scrapedData.novelTitle !== '제목없음') {
|
||||
bookData.fileName = scrapedData.novelTitle;
|
||||
}
|
||||
|
||||
// 중복 챕터 검사
|
||||
const isDuplicate = bookData.chapters.some(chap => chap.chapterId === chapterId);
|
||||
if (isDuplicate) {
|
||||
console.log(`⚠️ 이미 저장된 챕터입니다 (ID: ${chapterId}). 자동 진행을 중지합니다.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 챕터 추가
|
||||
bookData.chapters.push({
|
||||
chapterId: chapterId,
|
||||
title: scrapedData.chapterTitle,
|
||||
content: scrapedData.content
|
||||
});
|
||||
|
||||
// Storage에 저장
|
||||
scrapedBooks[bookId] = bookData;
|
||||
chrome.storage.local.set({
|
||||
scrapedBooks: scrapedBooks,
|
||||
currentBookId: bookId
|
||||
}, async () => {
|
||||
console.log(`✅ [${scrapedData.novelTitle} - ${scrapedData.chapterTitle}] 저장 완료!`);
|
||||
|
||||
// ⏳ 5. 저장 완료 후 2~3초 랜덤 대기
|
||||
const waitDelay = Math.floor(Math.random() * (5000 - 2000 + 1)) + 4000;
|
||||
console.log(`${(waitDelay / 1000).toFixed(1)}초 대기 후 다음 챕터로 이동합니다... ⏳`);
|
||||
await new Promise(resolve => setTimeout(resolve, waitDelay));
|
||||
|
||||
// '다음화' 버튼 클릭
|
||||
const buttons = Array.from(document.querySelectorAll('a.btn.btn-black.btn-sm'));
|
||||
const nextButton = buttons.find(btn => btn.innerText.trim().includes('다음화'));
|
||||
|
||||
if (nextButton) {
|
||||
console.log("👉 다음 화 버튼 클릭 진행");
|
||||
nextButton.click();
|
||||
} else {
|
||||
console.log("⚠️ '다음화' 버튼을 찾을 수 없거나 마지막 화입니다.");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🚀 화면 높이의 약 80%씩 큼직하게 스크롤하는 함수
|
||||
// ==========================================
|
||||
function pageSkimScroll(duration) {
|
||||
return new Promise((resolve) => {
|
||||
let elapsed = 0;
|
||||
|
||||
const scrollLoop = () => {
|
||||
if (elapsed >= duration) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 400ms ~ 700ms 사이의 랜덤한 대기 시간 (큼직하게 내리기 때문에 간격을 조금 더 줌)
|
||||
const stepTime = Math.floor(Math.random() * (1700 - 400 + 1)) + 1400;
|
||||
|
||||
// 현재 브라우저 창 높이(Viewport)를 구함
|
||||
const screenHeight = window.innerHeight;
|
||||
|
||||
// 75% ~ 85% 사이의 랜덤한 비율 설정 (평균 80%)
|
||||
const scrollRatio = 0.75 + (Math.random() * 0.1);
|
||||
const stepAmount = screenHeight * scrollRatio;
|
||||
|
||||
// 부드럽게 스크롤
|
||||
window.scrollBy({ top: stepAmount, behavior: 'smooth' });
|
||||
|
||||
elapsed += stepTime;
|
||||
setTimeout(scrollLoop, stepTime);
|
||||
};
|
||||
|
||||
// 루프 시작
|
||||
scrollLoop();
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 스크래핑 헬퍼 함수
|
||||
// ==========================================
|
||||
function scrapePage() {
|
||||
const titleEl = document.querySelector('.page-title h2');
|
||||
let novelTitle = titleEl ? titleEl.innerText.trim() : '제목없음';
|
||||
|
||||
let chapterTitle = document.querySelector('.theme-novel-title');
|
||||
chapterTitle = chapterTitle ? chapterTitle.innerText.trim() : '1화';
|
||||
|
||||
let novelContent = '';
|
||||
const contentHost = document.querySelector('.theme-novel-content');
|
||||
|
||||
if (contentHost) {
|
||||
if (contentHost.shadowRoot) {
|
||||
const pTags = contentHost.shadowRoot.querySelectorAll('p');
|
||||
const textArray = Array.from(pTags).map(p => p.innerText.trim());
|
||||
novelContent = textArray.join('\n\n');
|
||||
} else {
|
||||
const template = contentHost.querySelector('template[shadowrootmode="open"]');
|
||||
if (template && template.content) {
|
||||
const pTags = template.content.querySelectorAll('p');
|
||||
const textArray = Array.from(pTags).map(p => p.textContent.trim());
|
||||
novelContent = textArray.join('\n\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!novelContent) {
|
||||
console.warn('본문을 추출할 수 없습니다.');
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
novelTitle: novelTitle,
|
||||
chapterTitle: chapterTitle,
|
||||
content: novelContent
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "웹소설 스크래퍼 (나만의 서재용)",
|
||||
"version": "1.2",
|
||||
"description": "웹소설 챕터를 수집하여 서재 리더기용 JSON으로 다운로드합니다.",
|
||||
"action": {
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"scripting",
|
||||
"storage",
|
||||
"downloads",
|
||||
"unlimitedStorage"
|
||||
],
|
||||
"host_permissions": [
|
||||
"https://api.telegram.org/*"
|
||||
],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://newtoki1.org/novel/*",
|
||||
"*://*.newtoki1.org/novel/*"
|
||||
],
|
||||
"js": ["content.js"],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body { width: 280px; padding: 15px; font-family: 'Malgun Gothic', sans-serif; background: #f9f9f9; }
|
||||
h3 { margin-top: 0; text-align: center; color: #333; }
|
||||
button { width: 100%; padding: 10px; margin-bottom: 8px; cursor: pointer; border: none; border-radius: 6px; font-weight: bold; font-size: 13px; transition: 0.2s; }
|
||||
button:hover { opacity: 0.9; }
|
||||
#btn-save { background: #3498db; color: white; }
|
||||
#btn-download { background: #27ae60; color: white; }
|
||||
#btn-telegram { background: #0088cc; color: white; } /* 텔레그램 시그니처 색상 */
|
||||
#btn-clear { background: #e74c3c; color: white; }
|
||||
|
||||
.tg-config { background: #fff; padding: 10px; border-radius: 6px; margin-bottom: 10px; border: 1px solid #ddd; }
|
||||
.tg-config input { width: 92%; padding: 6px; margin-top: 4px; margin-bottom: 8px; font-size: 11px; border: 1px solid #ccc; border-radius: 4px; }
|
||||
.tg-config label { font-size: 11px; font-weight: bold; color: #555; }
|
||||
|
||||
#status { font-size: 12px; color: #666; text-align: center; margin-top: 5px; padding: 10px; background: #eee; border-radius: 6px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>📖 소설 스크래퍼</h3>
|
||||
|
||||
<div class="tg-config">
|
||||
<label>Bot Token:</label>
|
||||
<input type="password" id="tg-token" placeholder="BotFather에게 받은 토큰">
|
||||
<label>Chat ID:</label>
|
||||
<input type="text" id="tg-chatid" placeholder="숫자로 된 Chat ID">
|
||||
<button id="btn-save-config" style="background:#666; color:#fff; padding:5px; font-size:11px; margin-bottom:0;">⚙️ 텔레그램 설정 저장</button>
|
||||
</div>
|
||||
|
||||
<button id="btn-save">➕ 현재 화면(챕터) 저장하기</button>
|
||||
<button id="btn-download">📥 리더기용 JSON 다운로드</button>
|
||||
<button id="btn-telegram">🚀 텔레그램으로 JSON 전송</button>
|
||||
<button id="btn-clear">🗑️ 현재 소설 데이터 초기화</button>
|
||||
|
||||
<div id="status">대기 중...</div>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,267 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
updateStatus();
|
||||
loadTelegramConfig();
|
||||
|
||||
// 1. [설정 저장] 버튼
|
||||
document.getElementById('btn-save-config').addEventListener('click', saveTelegramConfig);
|
||||
|
||||
// 2. [저장하기] 버튼
|
||||
// 2. [저장하기] 버튼
|
||||
document.getElementById('btn-save').addEventListener('click', async () => {
|
||||
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
|
||||
chrome.scripting.executeScript({
|
||||
target: { tabId: tab.id },
|
||||
function: scrapePage
|
||||
}, (results) => {
|
||||
if (results && results[0] && results[0].result) {
|
||||
const data = results[0].result;
|
||||
const match = tab.url ? tab.url.match(/\/novel\/(\d+)\/(\d+)/) : null;
|
||||
const bookId = match ? match[1] : 'manual_' + Date.now();
|
||||
const chapterId = match ? match[2] : 'manual_chap_' + Date.now(); // 챕터 ID 추가
|
||||
|
||||
// chapterId를 같이 넘겨줍니다.
|
||||
saveToExtensionStorage(data, bookId, chapterId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 3. [다운로드] 버튼
|
||||
document.getElementById('btn-download').addEventListener('click', downloadJson);
|
||||
|
||||
// 4. [텔레그램 전송] 버튼
|
||||
document.getElementById('btn-telegram').addEventListener('click', sendToTelegram);
|
||||
|
||||
// 5. [초기화] 버튼
|
||||
document.getElementById('btn-clear').addEventListener('click', clearStorage);
|
||||
});
|
||||
|
||||
// 텔레그램 설정 불러오기
|
||||
function loadTelegramConfig() {
|
||||
chrome.storage.local.get(['tgToken', 'tgChatId'], (result) => {
|
||||
if (result.tgToken) document.getElementById('tg-token').value = result.tgToken;
|
||||
if (result.tgChatId) document.getElementById('tg-chatid').value = result.tgChatId;
|
||||
});
|
||||
}
|
||||
|
||||
// 텔레그램 설정 저장
|
||||
function saveTelegramConfig() {
|
||||
const token = document.getElementById('tg-token').value.trim();
|
||||
const chatId = document.getElementById('tg-chatid').value.trim();
|
||||
|
||||
chrome.storage.local.set({ tgToken: token, tgChatId: chatId }, () => {
|
||||
alert("✅ 텔레그램 설정이 저장 되었습니다!");
|
||||
});
|
||||
}
|
||||
|
||||
// 🚀 텔레그램 API로 JSON 파일 전송 함수
|
||||
function sendToTelegram() {
|
||||
chrome.storage.local.get(['scrapedBooks', 'currentBookId', 'tgToken', 'tgChatId'], async (result) => {
|
||||
const token = result.tgToken;
|
||||
const chatId = result.tgChatId;
|
||||
|
||||
if (!token || !chatId) {
|
||||
alert("⚠️ 먼저 텔레그램 Bot Token과 Chat ID를 설정하고 저장해주세요!");
|
||||
return;
|
||||
}
|
||||
|
||||
const books = result.scrapedBooks || {};
|
||||
const currentBookId = result.currentBookId;
|
||||
const bookData = currentBookId ? books[currentBookId] : null;
|
||||
|
||||
if (!bookData || bookData.chapters.length === 0) {
|
||||
alert("전송할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 리더기 포맷 페이로드 생성
|
||||
const payload = {
|
||||
type: 'single_book',
|
||||
book: bookData,
|
||||
progress: { chapter: 0, page: 0, tags: [], memo: "스크래퍼 확장프로그램으로 수집됨", isFavorite: false, isCompleted: false }
|
||||
};
|
||||
|
||||
const jsonString = JSON.stringify(payload, null, 2);
|
||||
const safeFileName = bookData.fileName.replace(/[\\/:*?"<>|]/g, '_');
|
||||
|
||||
// JSON 문자열을 Blob 파일 객체로 변환
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
|
||||
// Multipart FormData 생성 (텔레그램 API 전송용)
|
||||
const formData = new FormData();
|
||||
formData.append('chat_id', chatId);
|
||||
formData.append('document', blob, `book_${safeFileName}.json`);
|
||||
formData.append('caption', `📖 [${bookData.fileName}]\n총 ${bookData.chapters.length}화 수집 완료 JSON 파일입니다.`);
|
||||
|
||||
// 버튼 상태 변경
|
||||
const btnTg = document.getElementById('btn-telegram');
|
||||
btnTg.innerText = "⏳ 전송 중...";
|
||||
btnTg.disabled = true;
|
||||
|
||||
try {
|
||||
// Telegram sendDocument API 호출
|
||||
const response = await fetch(`https://api.telegram.org/bot${token}/sendDocument`, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const resData = await response.json();
|
||||
|
||||
if (resData.ok) {
|
||||
alert(`🚀 [${bookData.fileName}] 텔레그램으로 전송 성공!`);
|
||||
} else {
|
||||
alert(`❌ 전송 실패: ${resData.description}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
alert("❌ 네트워크 오류가 발생했습니다.");
|
||||
} finally {
|
||||
btnTg.innerText = "🚀 텔레그램으로 JSON 전송";
|
||||
btnTg.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 스크래핑 함수 (수동 저장용)
|
||||
function scrapePage() {
|
||||
const titleEl = document.querySelector('.page-title h2');
|
||||
let novelTitle = titleEl ? titleEl.innerText.trim() : '제목없음';
|
||||
|
||||
let chapterTitle = document.querySelector('.theme-novel-title');
|
||||
chapterTitle = chapterTitle ? chapterTitle.innerText.trim() : '1화';
|
||||
|
||||
let novelContent = '';
|
||||
const contentHost = document.querySelector('.theme-novel-content');
|
||||
|
||||
if (contentHost) {
|
||||
if (contentHost.shadowRoot) {
|
||||
const pTags = contentHost.shadowRoot.querySelectorAll('p');
|
||||
const textArray = Array.from(pTags).map(p => p.innerText.trim());
|
||||
novelContent = textArray.join('\n\n');
|
||||
} else {
|
||||
const template = contentHost.querySelector('template[shadowrootmode="open"]');
|
||||
if (template && template.content) {
|
||||
const pTags = template.content.querySelectorAll('p');
|
||||
const textArray = Array.from(pTags).map(p => p.textContent.trim());
|
||||
novelContent = textArray.join('\n\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!novelContent) {
|
||||
alert('본문을 추출할 수 없습니다.');
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
novelTitle: novelTitle,
|
||||
chapterTitle: chapterTitle,
|
||||
content: novelContent
|
||||
};
|
||||
}
|
||||
|
||||
// 수동 저장 함수
|
||||
function saveToExtensionStorage(scrapedData, bookId) {
|
||||
chrome.storage.local.get(['scrapedBooks'], (result) => {
|
||||
let scrapedBooks = result.scrapedBooks || {};
|
||||
|
||||
if (!scrapedBooks[bookId]) {
|
||||
scrapedBooks[bookId] = {
|
||||
id: 'book_' + bookId,
|
||||
fileName: scrapedData.novelTitle,
|
||||
chapters: []
|
||||
};
|
||||
}
|
||||
|
||||
let bookData = scrapedBooks[bookId];
|
||||
|
||||
// 챕터 ID 기준으로 중복 검사
|
||||
const isDuplicate = bookData.chapters.some(chap => chap.chapterId === chapterId);
|
||||
if (isDuplicate) {
|
||||
alert('⚠️ 이미 저장된 챕터입니다!');
|
||||
return;
|
||||
}
|
||||
|
||||
bookData.chapters.push({
|
||||
chapterId: chapterId,
|
||||
title: scrapedData.chapterTitle,
|
||||
content: scrapedData.content
|
||||
});
|
||||
scrapedBooks[bookId] = bookData;
|
||||
|
||||
chrome.storage.local.set({ scrapedBooks: scrapedBooks, currentBookId: bookId }, () => {
|
||||
updateStatus();
|
||||
alert(`✅ [${scrapedData.chapterTitle}] 저장 완료!`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 다운로드 함수
|
||||
function downloadJson() {
|
||||
chrome.storage.local.get(['scrapedBooks', 'currentBookId'], (result) => {
|
||||
const books = result.scrapedBooks || {};
|
||||
const currentBookId = result.currentBookId;
|
||||
const bookData = currentBookId ? books[currentBookId] : null;
|
||||
|
||||
if (!bookData || bookData.chapters.length === 0) {
|
||||
alert("다운로드할 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
type: 'single_book',
|
||||
book: bookData,
|
||||
progress: { chapter: 0, page: 0, tags: [], memo: "스크래퍼 확장프로그램으로 수집됨", isFavorite: false, isCompleted: false }
|
||||
};
|
||||
|
||||
const jsonString = JSON.stringify(payload, null, 2);
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const safeFileName = bookData.fileName.replace(/[\\/:*?"<>|]/g, '_');
|
||||
|
||||
chrome.downloads.download({
|
||||
url: url,
|
||||
filename: `book_${safeFileName}.json`,
|
||||
saveAs: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 초기화 함수
|
||||
function clearStorage() {
|
||||
chrome.storage.local.get(['scrapedBooks', 'currentBookId'], (result) => {
|
||||
const books = result.scrapedBooks || {};
|
||||
const currentBookId = result.currentBookId;
|
||||
|
||||
if (!currentBookId || !books[currentBookId]) {
|
||||
alert("삭제할 수집 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const bookTitle = books[currentBookId].fileName;
|
||||
if(confirm(`[${bookTitle}] 수집 데이터를 삭제하시겠습니까?`)) {
|
||||
delete books[currentBookId];
|
||||
chrome.storage.local.set({ scrapedBooks: books, currentBookId: null }, () => {
|
||||
updateStatus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 상태창 업데이트
|
||||
function updateStatus() {
|
||||
chrome.storage.local.get(['scrapedBooks', 'currentBookId'], (result) => {
|
||||
const books = result.scrapedBooks || {};
|
||||
const currentBookId = result.currentBookId;
|
||||
const book = currentBookId ? books[currentBookId] : null;
|
||||
|
||||
const count = book ? book.chapters.length : 0;
|
||||
const title = book ? book.fileName : '없음';
|
||||
|
||||
document.getElementById('status').innerHTML = `
|
||||
<strong>현재 선택 소설:</strong> ${title}<br>
|
||||
<strong style="color:#27ae60; font-size:14px;">모인 챕터: ${count}화</strong>
|
||||
`;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
(function() {
|
||||
var retryCount = 0;
|
||||
var maxRetries = 2;
|
||||
|
||||
function tryExtract() {
|
||||
try {
|
||||
const newUrl = window.location.origin + window.location.pathname;
|
||||
const hostname = window.location.hostname;
|
||||
const contentsType = hostname.includes("book") ? "booktoki" :
|
||||
hostname.includes("mana") ? "manatoki" :
|
||||
hostname.includes("new") ? "newtoki" : "web";
|
||||
|
||||
// 1. 목차(List) 감지 로직
|
||||
const listBody = document.querySelector(".list-body");
|
||||
const novelContent = document.querySelector("#novel_content");
|
||||
|
||||
// [중요] 두 핵심 요소가 모두 없으면 재시도 결정
|
||||
if (!listBody && !novelContent) {
|
||||
if (retryCount < maxRetries) {
|
||||
retryCount++;
|
||||
console.log("DEBUG_LOG: [JS] 요소를 찾지 못해 재시도 중... (" + retryCount + ")");
|
||||
setTimeout(tryExtract, 500); // 0.5초 후 다시 실행
|
||||
return;
|
||||
} else {
|
||||
console.log("DEBUG_LOG: [JS] 최대 재시도 횟수 초과");
|
||||
window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
|
||||
'type': 'JP',
|
||||
'currentUrl' : newUrl
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 1. 목차 추출 실행 ---
|
||||
if (listBody !== null) {
|
||||
const contentsArray = [];
|
||||
const children = listBody.children;
|
||||
const bookTitleEl = document.querySelector('.view-title span');
|
||||
const bookTitle = bookTitleEl ? bookTitleEl.innerText.trim() : "Unknown";
|
||||
const pagination = document.querySelector(".pagination");
|
||||
let nextPagingUrl = null;
|
||||
|
||||
if (pagination) {
|
||||
const activeLi = pagination.querySelector("li.active");
|
||||
if (activeLi && activeLi.nextElementSibling) {
|
||||
const nextA = activeLi.nextElementSibling.querySelector("a");
|
||||
// 다음 엘리먼트가 존재하고, 'disabled' 클래스가 없으며, href가 있는 경우
|
||||
if (nextA && nextA.href && !activeLi.nextElementSibling.classList.contains("disabled")) {
|
||||
nextPagingUrl = nextA.href;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
try {
|
||||
const wrNumEl = children[i].getElementsByClassName('wr-num')[0];
|
||||
const wrSubjectA = children[i].getElementsByClassName('wr-subject')[0]?.getElementsByTagName('a')[0];
|
||||
if (!wrNumEl || !wrSubjectA) continue;
|
||||
|
||||
let pageUrl = new URL(wrSubjectA.href, window.location.origin).pathname;
|
||||
let paths = pageUrl.split('/').filter(p => p);
|
||||
if (paths.length > 0) {
|
||||
var lastPart = paths[paths.length - 1];
|
||||
var isOnlyNumber = lastPart && Array.from(lastPart).every(ch => ch >= '0' && ch <= '9');
|
||||
if (!isOnlyNumber) paths.pop();
|
||||
}
|
||||
pageUrl = "/" + paths.join('/');
|
||||
|
||||
contentsArray.push({
|
||||
'chapterID': parseInt(wrNumEl.textContent.replace(/[^0-9]/g, "")),
|
||||
'chapterNum': parseInt(wrNumEl.textContent.replace(/[^0-9]/g, "")),
|
||||
'pathUrl': pageUrl,
|
||||
'contentsType': contentsType,
|
||||
'bookPageUrl': window.location.pathname,
|
||||
'chapterTitle': wrSubjectA.innerText.split('\n').pop().trim(),
|
||||
'bookTitle': bookTitle,
|
||||
'currentUrl' : newUrl
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (contentsArray.length > 0) {
|
||||
window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
|
||||
'type': 'getListResult',
|
||||
'contentsType': contentsType,
|
||||
'bookTitle': bookTitle,
|
||||
'bookPageUrl': window.location.pathname,
|
||||
'pages': contentsArray,
|
||||
'currentUrl' : newUrl,
|
||||
'nextPagingUrl': nextPagingUrl
|
||||
}));
|
||||
return; // 전송 성공 시 종료
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. 본문 추출 실행 ---
|
||||
if (novelContent !== null) {
|
||||
const titleEl = document.querySelector(".page-desc");
|
||||
const chapterTitle = titleEl ? titleEl.innerText.trim() : "";
|
||||
const contents = novelContent.innerText.trim();
|
||||
|
||||
|
||||
if (contents.length > 100) {
|
||||
window.webkit.messageHandlers.ContentsRcv.postMessage(JSON.stringify({
|
||||
'type': 'BookContents',
|
||||
'chapterTitle': chapterTitle,
|
||||
'bookContents': contents,
|
||||
'pageUrl' : window.location.pathname,
|
||||
'currentUrl' : newUrl
|
||||
}));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Unified Script Error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// 최초 실행
|
||||
tryExtract();
|
||||
})();
|
||||
@@ -62,4 +62,14 @@
|
||||
//// // 앱으로 오류 신호 전달
|
||||
//// browser.runtime.sendMessage({ type: 'RELOAD_REQUEST' });
|
||||
//// }
|
||||
////});
|
||||
////});
|
||||
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
function(details) {
|
||||
console.log("Request intercepted for URL:", details.url);
|
||||
// 이 예시는 단순히 로그를 남기므로 요청을 변경하거나 차단하지 않음
|
||||
return {};
|
||||
},
|
||||
{urls: ["<all_urls>"]}, // 모든 URL에 대해 요청 듣기
|
||||
[]
|
||||
);
|
||||
@@ -0,0 +1,85 @@
|
||||
// ==========================================
|
||||
// 1. 챕터를 로컬 스토리지에 누적 저장하는 함수
|
||||
// ==========================================
|
||||
function saveChapterToLocal(bookTitle, chapterTitle, chapterContent) {
|
||||
const STORAGE_KEY = 'webReader_scraper_temp';
|
||||
let bookData = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
|
||||
// 기존 데이터가 없거나, 다른 책을 스크랩하기 시작한 경우 초기화
|
||||
if (!bookData || bookData.fileName !== bookTitle) {
|
||||
bookData = {
|
||||
id: 'book_scraped_' + Date.now(), // 고유 ID 생성
|
||||
fileName: bookTitle,
|
||||
chapters: []
|
||||
};
|
||||
console.log(`새로운 책 [${bookTitle}] 스크랩을 시작합니다.`);
|
||||
}
|
||||
|
||||
// 중복 저장 방지 로직 (동일한 챕터 제목이 있는지 검사)
|
||||
const isDuplicate = bookData.chapters.some(chap => chap.title === chapterTitle);
|
||||
if (isDuplicate) {
|
||||
console.warn(`⚠️ 이미 저장된 챕터입니다: ${chapterTitle}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 챕터 데이터 추가
|
||||
bookData.chapters.push({
|
||||
title: chapterTitle,
|
||||
content: chapterContent
|
||||
});
|
||||
|
||||
// 변경된 데이터를 다시 스토리지에 저장
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(bookData));
|
||||
console.log(`✅ [${bookTitle}] ${chapterTitle} 저장 완료! (현재 총 ${bookData.chapters.length}화)`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. 누적된 데이터를 리더기 호환 JSON으로 다운로드하는 함수
|
||||
// ==========================================
|
||||
function downloadBookAsJson() {
|
||||
const STORAGE_KEY = 'webReader_scraper_temp';
|
||||
const bookData = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
|
||||
if (!bookData || !bookData.chapters || bookData.chapters.length === 0) {
|
||||
alert("다운로드할 챕터 데이터가 없습니다. 먼저 챕터를 저장해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// ★ 리더기의 '개별 책 복원' 형식과 완벽히 일치하도록 페이로드 구성
|
||||
const payload = {
|
||||
type: 'single_book',
|
||||
book: bookData,
|
||||
progress: {
|
||||
chapter: 0,
|
||||
page: 0,
|
||||
tags: [], // 리더기에서 불러올 때 재분석 기능으로 태그를 달 수 있습니다.
|
||||
memo: "스크랩을 통해 추가된 소설입니다.",
|
||||
isFavorite: false,
|
||||
isCompleted: false
|
||||
}
|
||||
};
|
||||
|
||||
// JSON 파일로 변환 및 다운로드 처리
|
||||
const jsonString = JSON.stringify(payload, null, 2);
|
||||
const blob = new Blob([jsonString], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
|
||||
// 파일명에 사용할 수 없는 특수문자 제거
|
||||
const safeFileName = bookData.fileName.replace(/[\\/:*?"<>|]/g, '_');
|
||||
a.download = `book_${safeFileName}.json`;
|
||||
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
// 다운로드 후 임시 데이터 정리
|
||||
if (confirm("파일 다운로드가 완료되었습니다.\n다음 스크랩을 위해 임시 저장된 데이터를 초기화할까요?")) {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
console.log("임시 데이터가 초기화되었습니다.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
sequences: {
|
||||
"www.nhmembers.co.kr/nhaob": [".btn-direct-menu"],
|
||||
"multicon.co.kr/couponMall/order/info":[
|
||||
{ target: () => document.querySelector(".point_inquiry").click(), wait: 5000 },
|
||||
{ action: () => {
|
||||
if(document.querySelector(".result_point").innerText.split("P")[0] > 0) {
|
||||
location.href = "${NH_DOMAIN + APP_LOG}"
|
||||
}
|
||||
}, wait: 15000 },
|
||||
],
|
||||
"multicon.co.kr/couponMall/goodsDetail":[
|
||||
{ target: () => document.querySelector(".grey_btn").click(), wait: 5000 }
|
||||
],
|
||||
"multicon.co.kr/couponMall/main":[
|
||||
{ target: () => document.querySelector(".product").parentElement.click(), wait: 5000 }
|
||||
],
|
||||
"example.com/login": [
|
||||
// 1. [순수 함수] 아이디 입력 (실행 후 바로 다음 스텝으로)
|
||||
{ action: () => { document.querySelector(".userid-input").value = "test_id"; } },
|
||||
|
||||
// 2. [순수 함수 + 대기] 비밀번호 입력 후 1초 대기
|
||||
{
|
||||
action: () => { document.querySelector(".password-input").value = "1234!!"; },
|
||||
wait: 1000
|
||||
},
|
||||
|
||||
// 3. [클릭 액션] 로그인 버튼 클릭 (기존 방식들 모두 호환됨)
|
||||
"#login-btn",
|
||||
{ target: () => document.getElementById("confirm-modal"), wait: 2000 }
|
||||
],
|
||||
"mysite.com/survey": ["input[value='yes']", "button.next-step"],
|
||||
},
|
||||
blacklist: {
|
||||
"any": ["logout", "delete", "remove", "exit","header__prev main_header"],
|
||||
"runcomm.co.kr": [".adpot_inquiry", ",btn_com1", "닫기"]
|
||||
}
|
||||
}
|
||||
@@ -83,4 +83,23 @@ function check2() {
|
||||
}
|
||||
}
|
||||
}
|
||||
check2();
|
||||
check2();
|
||||
|
||||
fetch("https://dv-m.nhmembers.co.kr/nhpot/common/saveCertInf.ajax",{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}
|
||||
})
|
||||
|
||||
if (document.querySelectorAll('[class^="w-full flex"]').length > 1) {
|
||||
document.querySelectorAll('[class^="w-full flex"]').forEach(function (e) {
|
||||
|
||||
|
||||
var description = ""
|
||||
if(e.querySelector('[class^="pb-2 w-100 text-gray-500"]')){
|
||||
description = e.querySelector('[class^="pb-2 w-100 text-gray-500"]').textContent.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
console.log(description)
|
||||
})
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
version: '3'
|
||||
services:
|
||||
couchdb:
|
||||
image: couchdb:latest
|
||||
container_name: couchdb
|
||||
restart: always
|
||||
ports:
|
||||
- "5984:5984" # 외부접근: 5984포트
|
||||
environment:
|
||||
- COUCHDB_USER=obsidian
|
||||
- COUCHDB_PASSWORD=HiVi88131921
|
||||
volumes:
|
||||
- ./data:/opt/couchdb/data
|
||||
@@ -1,93 +1 @@
|
||||
video-item ::> <div class="img-area">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a onclick="sendEvent('Cover Click','Main List Movie','201882')" href="/movie/ipzz-574-201882" data-link="https://images.ijavtorrent.com/data/covers/201882.jpg"> <img sizes="
|
||||
(max-width: 1536px) 480px,
|
||||
(max-width: 1920px) 620px,
|
||||
(min-width: 1921px) 800px,
|
||||
" src="https://images.ijavtorrent.com/data/covers/201882.jpg" alt="IPZZ-574 I Didn't Know About My Wife's Twisted Sexual Habits... My Beloved Wife, Who Is Usually Kind, Was A Masochistic Slave Trained By A Sadistic Neighbor. Kana Momonogi" title="IPZZ-574 I Didn't Know About My Wife's Twisted Sexual Habits... My Beloved Wife, Who Is Usually Kind, Was A Masochistic Slave Trained By A Sadistic Neighbor. Kana Momonogi" class="lazy mw-100" style="" srcset="
|
||||
https://images.ijavtorrent.com/data/covers/201882.jpg?width=480 480w,
|
||||
https://images.ijavtorrent.com/data/covers/201882.jpg?width=620 620w,
|
||||
https://images.ijavtorrent.com/data/covers/201882.jpg?width=800 800w,
|
||||
"> </a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="name">
|
||||
<a onclick="sendEvent('movie-click','Main List Movie','201882')" href="/movie/ipzz-574-201882"> <span>ipzz-574 i didn't know about my wife's twisted sexual habits... my beloved wife, who is usually kind, was a masochistic slave trained by a sadistic neighbor. kana momonogi</span> </a>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<a onclick="sendEvent('movie-click','Main List Movie','201882')" href="/movie/ipzz-574-201882"> 08/07/2025 </a> | <i class="fas fa-eye"></i> <span class="pageview-value">4260</span> | <i class="fa fa-fw fa-download"></i> <span class="download-value">2602</span>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<div class="badge badge-info" data-toggle="popover" data-html="true" data-content="<div><img src='https://images.ijavtorrent.com/data/actresses/451.jpg?v=772750732' alt='Kana Momonogi' style='width: 150px; height: 150px;'></div>" data-original-title="" title="">
|
||||
<a href="/actress/kana-momonogi-451"> <i class="fas fa-info"></i> Kana Momonogi </a> <img src="https://images.ijavtorrent.com/data/actresses/451.jpg?v=772750732" class="d-none">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="badge badge-warning">
|
||||
<a href="/?editorrate=6"><i class="fab fa-hotjar"></i> 6</a>
|
||||
</div>
|
||||
<div class="badge badge-warning">
|
||||
<a href="/tag/top-5-daily-2483">Top 5 Daily</a>
|
||||
</div>
|
||||
<div class="badge badge-secondary">
|
||||
<a href="/tag/cuckold-112">Cuckold</a>
|
||||
</div>
|
||||
<div class="badge badge-secondary">
|
||||
<a href="/tag/nasty-hardcore-85">Nasty, Hardcore</a>
|
||||
</div>
|
||||
<div class="badge badge-secondary">
|
||||
<a href="/tag/sm-95">SM</a>
|
||||
</div>
|
||||
<div class="badge badge-secondary">
|
||||
<a href="/tag/solowork-1">Solowork</a>
|
||||
</div>
|
||||
<div class="badge badge-secondary">
|
||||
<a href="/tag/married-woman-19">Married Woman</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="btn btn-sm btn-warning">
|
||||
<a onclick="sendEvent('Screenshot-Click','Main List Movie','201882')" href="https://images.ijavtorrent.com/data/screenshots/201882.jpg" data-featherlight="image" target="_blank"> <i class="far fa-images"></i> Screenshot </a>
|
||||
</div>
|
||||
<div class="btn btn-sm btn-outline-primary movie-like-button" data-movie-id="201882">
|
||||
<i class="fas fa-heart"></i> <span class="like-value">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-sm mt-2">
|
||||
<tbody>
|
||||
<tr style="vertical-align: middle">
|
||||
2025-07-23 11:22:20.062 26023-26023 Lunatic bums.lunatic.launcher E <td><a onclick="sendEvent('Torrent Click','Main List Movie','201882')" href="/download/463171" rel="nofollow" class="download-click-track"><i class="fa fa-fw fa-download"></i> Download</a> <a onclick="sendEvent('Magnet Click','Main List Movie','201882')" href="magnet:?xt=urn:btih:8c64238f2bfd260a6793b3b8ec97aad93e4d1dd8&amp;dn=IPZZ-574%E3%80%90%E7%A0%B4%E5%A3%8A%E7%89%88%E3%80%91%E4%BF%BA%E3%81%AE%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84%E5%A6%BB%E3%81%AE%E6%AD%AA%E3%82%93%E3%81%A0%E6%80%A7%E7%99%96%E2%80%A6%20%E6%99%AE%E6%AE%B5%E5%84%AA%E3%81%97%E3%81%84%E6%9C%80%E6%84%9B%E3%81%AE%E5%A6%BB%E3%81%AF%E3%83%89S%E9%9A%A3%E4%BA%BA%E3%81%AB%E8%AA%BF%E6%95%99%E6%B8%88%E3%81%AE%E3%83%9E%E3%82%BE%E5%A5%B4%E2%97%8F%E3%81%A7%E3%81%97%E3%81%9F%E3%80%82%20%E6%A1%83%E4%B9%83%E6%9C%A8%E3%81%8B%E3%81%AA&amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce" rel="nofollow" class="magnet-click-track"><i class="fa fa-fw fa-magnet" rel="nofollow"></i> Magnet</a></td>
|
||||
<td><i class="fas fa-weight-hanging"></i> 3.4gb</td>
|
||||
<td><strong>S:</strong> 41</td>
|
||||
<td><strong>L:</strong> 667</td>
|
||||
<td><i class="far fa-calendar-alt"></i> 23/07/25</td>
|
||||
<td><span class="badge badge-info">Decen</span></td>
|
||||
</tr>
|
||||
<tr style="vertical-align: middle">
|
||||
<td><a onclick="sendEvent('Torrent Click','Main List Movie','201882')" href="/download/459739" rel="nofollow" class="download-click-track"><i class="fa fa-fw fa-download"></i> Download</a> <a onclick="sendEvent('Magnet Click','Main List Movie','201882')" href="magnet:?xt=urn:btih:6a020162885ec725961eeca6ccb15153586f09d3&amp;dn=%5BHD%2F720p%5D%20IPZZ-574%20%E4%BF%BA%E3%81%AE%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84%E5%A6%BB%E3%81%AE%E6%AD%AA%E3%82%93%E3%81%A0%E6%80%A7%E7%99%96%E2%80%A6%20%E6%99%AE%E6%AE%B5%E5%84%AA%E3%81%97%E3%81%84%E6%9C%80%E6%84%9B%E3%81%AE%E5%A6%BB%E3%81%AF%E3%83%89S%E9%9A%A3%E4%BA%BA%E3%81%AB%E8%AA%BF%E6%95%99%E6%B8%88%E3%81%AE%E3%83%9E%E3%82%BE%E5%A5%B4%E2%97%8F%E3%81%A7%E3%81%97%E3%81%9F%E3%80%82%20%E6%A1%83%E4%B9%83%E6%9C%A8%E3%81%8B%E3%81%AA&amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce" rel="nofollow" class="magnet-click-track"><i class="fa fa-fw fa-magnet" rel="nofollow"></i> Magnet</a></td>
|
||||
<td><i class="fas fa-weight-hanging"></i> 1.3gb</td>
|
||||
<td><strong>S:</strong> 30</td>
|
||||
<td><strong>L:</strong> 6</td>
|
||||
<td><i class="far fa-calendar-alt"></i> 22/07/25</td>
|
||||
</tr>
|
||||
<tr style="vertical-align: middle">
|
||||
2025-07-23 11:22:20.062 26023-26023 Lunatic bums.lunatic.launcher E <td><a onclick="sendEvent('Torrent Click','Main List Movie','201882')" href="/download/460809" rel="nofollow" class="download-click-track"><i class="fa fa-fw fa-download"></i> Download</a> <a onclick="sendEvent('Magnet Click','Main List Movie','201882')" href="magnet:?xt=urn:btih:cb582ed50fb3d342c2c668d2a33f7b143e1f1b03&amp;dn=%2B%2B%2B%20%5BFHDC%5D%20IPZZ-574%20%E4%BF%BA%E3%81%AE%E7%9F%A5%E3%82%89%E3%81%AA%E3%81%84%E5%A6%BB%E3%81%AE%E6%AD%AA%E3%82%93%E3%81%A0%E6%80%A7%E7%99%96%E2%80%A6%20%E6%99%AE%E6%AE%B5%E5%84%AA%E3%81%97%E3%81%84%E6%9C%80%E6%84%9B%E3%81%AE%E5%A6%BB%E3%81%AF%E3%83%89S%E9%9A%A3%E4%BA%BA%E3%81%AB%E8%AA%BF%E6%95%99%E6%B8%88%E3%81%AE%E3%83%9E%E3%82%BE%E5%A5%B4%E2%97%8F%E3%81%A7%E3%81%97%E3%81%9F%E3%80%82%20%E6%A1%83%E4%B9%83%E6%9C%A8%E3%81%8B%E3%81%AA&amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce" rel="nofollow" class="magnet-click-track"><i class="fa fa-fw fa-magnet" rel="nofollow"></i> Magnet</a></td>
|
||||
<td><i class="fas fa-weight-hanging"></i> 5.3gb</td>
|
||||
<td><strong>S:</strong> 60</td>
|
||||
<td><strong>L:</strong> 23</td>
|
||||
<td><i class="far fa-calendar-alt"></i> 22/07/25</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="text-right">
|
||||
<a href="/movie/ipzz-574-201882"> more torrents >> </a>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="mb-4">
|
||||
</div>
|
||||
java --telegram.bot.key=bot7934509464:AAE_xUbICxMdywLGnxo7BkeIqA1nVza4P9w --telegram.my.id=71476436 --telegram.target.id=71476436 --weather.api.key=de574a260b1f474d99955729241909 --spring.datasource.url=jdbc:mariadb://mra.sbspace.synology.me --spring.data.mongodb.uri=mongodb://lun_admin:VioPup*383@mongo.sbspace.synology.me/?wtimeoutMS=300&connectTimeoutMS=500&socketTimeoutMS=200 --spring.data.mongodb.database=lun_db --spring.datasource.username=lun_admin --spring.datasource.password=VioPup*383 --resource.handler=blog/post/image/** --resource.location=file:///usr/src/app/imgUpload --image.upload.path=/usr/src/app/imgUpload --api.gg.place=AIzaSyARLXyvmr_554tOy3UCh3naFlZQS3-qQQM
|
||||
@@ -0,0 +1,9 @@
|
||||
//(function() {
|
||||
// var meta = document.querySelector('meta[name=viewport]');
|
||||
// if (!meta) {
|
||||
// meta = document.createElement('meta');
|
||||
// meta.name = 'viewport';
|
||||
// document.head.appendChild(meta);
|
||||
// }
|
||||
// meta.setAttribute('content', 'width=device-width, initial-scale=1.0');
|
||||
//})();
|
||||
@@ -9,15 +9,18 @@
|
||||
|
||||
"name": "Sample Extension",
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
"scripts": ["Dotax.js", "background.js"]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"run_at": "document_start",
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["messaging.js"]
|
||||
"js": ["messaging.js","inject-viewport.js"]
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"cookies",
|
||||
"<all_urls>",
|
||||
"nativeMessaging",
|
||||
"nativeMessagingFromContent",
|
||||
"geckoViewAddons",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,384 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Synology Photos Random Slideshow</title>
|
||||
<style>
|
||||
/* 기본 스타일링 */
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: sans-serif;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* 로그인 화면 스타일 */
|
||||
#login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
padding: 30px;
|
||||
background: #222;
|
||||
border-radius: 8px;
|
||||
}
|
||||
#login-form input {
|
||||
padding: 10px;
|
||||
border: 1px solid #444;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#login-form button {
|
||||
padding: 10px;
|
||||
background: #007bff;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 사진이 표시될 컨테이너 */
|
||||
#photo-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none; /* 처음에는 숨김 */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/* 이미지 스타일 */
|
||||
#slideshow-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain; /* 이미지 비율 유지 */
|
||||
/* 부드러운 전환 효과 */
|
||||
opacity: 0;
|
||||
transition: opacity 1.5s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="login-form">
|
||||
<h2>시놀로지 포토 로그인</h2>
|
||||
<input type="text" id="nas-address" placeholder="NAS 주소 (예: 192.168.0.100)">
|
||||
<input type="text" id="username" placeholder="사용자 ID">
|
||||
<input type="password" id="password" placeholder="비밀번호">
|
||||
<button onclick="startSlideshow()">슬라이드쇼 시작</button>
|
||||
<p id="message" style="color: #ffdddd; text-align: center;"></p>
|
||||
</div>
|
||||
|
||||
<div id="photo-container">
|
||||
<img id="slideshow-image" alt="Loading photo...">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 전역 변수 설정
|
||||
let sid = '';
|
||||
let nasAddress = '';
|
||||
const allPhotoIds = [];
|
||||
let slideshowInterval;
|
||||
|
||||
// 메시지 표시 함수
|
||||
function showMessage(msg) {
|
||||
document.getElementById('message').innerText = msg;
|
||||
}
|
||||
|
||||
// 슬라이드쇼 시작 함수
|
||||
async function startSlideshow() {
|
||||
nasAddress = document.getElementById('nas-address').value.trim();
|
||||
const username = document.getElementById('username').value.trim();
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
if (!nasAddress || !username || !password) {
|
||||
showMessage('모든 정보를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
showMessage('로그인 중...');
|
||||
|
||||
try {
|
||||
// 1. 로그인하여 세션 ID (sid) 얻기
|
||||
const loginUrl = `https://${nasAddress}/webapi/auth.cgi?api=SYNO.API.Auth&version=7&method=login&account=${username}&passwd=${password}&session=SynologyPhotos&format=sid`;
|
||||
const loginResponse = await fetch(loginUrl,{
|
||||
mode: 'no-cors'
|
||||
});
|
||||
const loginData = await loginResponse.json();
|
||||
|
||||
if (loginData.success && loginData.data.sid) {
|
||||
sid = loginData.data.sid;
|
||||
showMessage('로그인 성공! 사진 목록을 가져옵니다...');
|
||||
|
||||
// 2. 전체 사진 목록 가져오기
|
||||
await fetchAllPhotos(0);
|
||||
|
||||
} else {
|
||||
showMessage('로그인 실패. 정보를 확인하세요.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showMessage('오류 발생. NAS 주소를 확인하세요.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < 100 ; i++) {
|
||||
// XMLHttpRequest 객체 생성
|
||||
console.log('try : ', i);
|
||||
const xhr = new XMLHttpRequest();
|
||||
var data = { EVT_ID : '10170'
|
||||
, EVT_DTL_TP_C : '0312'
|
||||
, WATER : 'Y'
|
||||
};
|
||||
xhr.open('POST', '/nhpot/maa/joinDailyEvt.ajax', true);
|
||||
// xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.onload = function () {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
// 요청 성공
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
console.log('성공:', response);
|
||||
} else {
|
||||
// 요청 실패
|
||||
console.error('실패:', xhr.statusText);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
console.error('네트워크 오류');
|
||||
};
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100 ; i++) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 지정된 시간(ms)만큼 기다리는 Promise를 반환합니다.
|
||||
* @param {number} ms - 기다릴 밀리초
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* API에 순차적으로 부하 테스트를 실행하는 함수
|
||||
* @param {number} totalCalls - 총 테스트 호출 횟수
|
||||
*/
|
||||
async function startSequentialLoadTest(totalCalls = 100) {
|
||||
// ⭐️ 여기에 테스트할 실제 API URL을 입력하세요.
|
||||
const API_ENDPOINT = 'https://api.example.com/your-endpoint';
|
||||
|
||||
let successfulCalls = 0;
|
||||
let failedCalls = 0;
|
||||
|
||||
console.log(`[부하 테스트 시작] 총 ${totalCalls}회 순차 호출 (매 1초 간격)`);
|
||||
console.log(`대상 URL: ${API_ENDPOINT}`);
|
||||
|
||||
for (let i = 1; i <= totalCalls; i++) {
|
||||
const startTime = performance.now(); // 요청 시작 시간
|
||||
|
||||
try {
|
||||
// 1. fetch 요청을 보내고 완료될 때까지 기다립니다.
|
||||
const response = await fetch("https://m.nhmembers.co.kr/nhpot/pnt/ajaxGetPntTupPointCvList.ajax", {
|
||||
"headers": {
|
||||
"accept": "*/*",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
"pragma": "no-cache",
|
||||
"sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Android WebView\";v=\"140\"",
|
||||
"sec-ch-ua-mobile": "?1",
|
||||
"sec-ch-ua-platform": "\"Android\"",
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"x-requested-with": "XMLHttpRequest"
|
||||
},
|
||||
"referrer": "https://m.nhmembers.co.kr/nhpot/pnt/pntTupPointCvIndex.snh?menuId=AC03050000",
|
||||
"body": null,
|
||||
"method": "POST",
|
||||
"mode": "cors",
|
||||
"credentials": "include"
|
||||
});
|
||||
|
||||
const duration = (performance.now() - startTime).toFixed(2); // 응답 시간
|
||||
|
||||
// 2. HTTP 응답 상태 코드로 성공/실패를 판단합니다.
|
||||
if (!response.ok) {
|
||||
// 200-299 범위 외의 상태 코드는 에러로 간주
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
// (선택 사항) 응답 데이터를 JSON으로 파싱
|
||||
// const data = await response.json();
|
||||
|
||||
console.log(`[${i}/${totalCalls}회] ✅ 성공 (상태: ${response.status}, ${duration}ms)`);
|
||||
successfulCalls++;
|
||||
|
||||
} catch (error) {
|
||||
// 3. 네트워크 오류 또는 fetch 실패 시 처리
|
||||
const duration = (performance.now() - startTime).toFixed(2);
|
||||
console.error(`[${i}/${totalCalls}회] ❌ 실패 (${error.message}, ${duration}ms)`);
|
||||
failedCalls++;
|
||||
}
|
||||
|
||||
// 4. 마지막 호출이 아닐 경우, 1초간 대기합니다.
|
||||
if (i < totalCalls) {
|
||||
await delay(50); // 1000ms = 1초
|
||||
}
|
||||
}
|
||||
|
||||
console.log('--------------------');
|
||||
console.log('[부하 테스트 완료]');
|
||||
console.log(`성공: ${successfulCalls}회`);
|
||||
console.log(`실패: ${failedCalls}회`);
|
||||
console.log('--------------------');
|
||||
}
|
||||
startSequentialLoadTest(500);
|
||||
|
||||
// 재귀적으로 모든 사진 ID를 가져오는 함수
|
||||
async function fetchAllPhotos(offset) {
|
||||
const limit = 5000; // 한 번에 5000개씩 요청
|
||||
const listUrl = `https://${nasAddress}/webapi/entry.cgi?api=SYNO.Foto.Browse.Item&version=1&method=list&limit=${limit}&offset=${offset}&_sid=${sid}`;
|
||||
const response = await fetch(listUrl);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
data.data.list.forEach(item => allPhotoIds.push(item.id));
|
||||
const total = data.data.total;
|
||||
|
||||
if (offset + limit < total) {
|
||||
// 받아올 사진이 더 있다면 다음 페이지 요청
|
||||
showMessage(`${allPhotoIds.length} / ${total} 장 로딩...`);
|
||||
await fetchAllPhotos(offset + limit);
|
||||
} else {
|
||||
// 모든 사진을 다 받아왔다면 슬라이드쇼 시작
|
||||
showMessage('사진 로딩 완료! 슬라이드쇼를 시작합니다.');
|
||||
document.getElementById('login-form').style.display = 'none';
|
||||
document.getElementById('photo-container').style.display = 'flex';
|
||||
|
||||
displayRandomPhoto(); // 첫 사진 표시
|
||||
// 10초마다 사진 변경
|
||||
slideshowInterval = setInterval(displayRandomPhoto, 10000);
|
||||
}
|
||||
} else {
|
||||
showMessage('사진 목록 가져오기 실패.');
|
||||
}
|
||||
}
|
||||
|
||||
// 랜덤 사진을 화면에 표시하는 함수
|
||||
function displayRandomPhoto() {
|
||||
if (allPhotoIds.length === 0) return;
|
||||
|
||||
// 랜덤하게 사진 ID 하나 선택
|
||||
const randomIndex = Math.floor(Math.random() * allPhotoIds.length);
|
||||
const photoId = allPhotoIds[randomIndex];
|
||||
|
||||
// 이미지 다운로드 URL 생성
|
||||
const imageUrl = `https://${nasAddress}/webapi/entry.cgi?api=SYNO.Foto.Download&version=1&method=download&force_download=true&item_id=%5B${photoId}%5D&_sid=${sid}`;
|
||||
|
||||
const imageElement = document.getElementById('slideshow-image');
|
||||
|
||||
// 이미지 Fade out
|
||||
imageElement.style.opacity = 0;
|
||||
|
||||
// 이미지가 완전히 사라진 후 새 이미지 로딩
|
||||
setTimeout(() => {
|
||||
imageElement.src = imageUrl;
|
||||
|
||||
// 새 이미지 로딩이 완료되면 Fade in
|
||||
imageElement.onload = () => {
|
||||
imageElement.style.opacity = 1;
|
||||
};
|
||||
}, 1500); // transition 시간과 동일하게 설정
|
||||
}
|
||||
|
||||
|
||||
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
async function testCall(totalCalls = 5000) {
|
||||
console.log(`현 주소 : ${location.href}`)
|
||||
var SNS_TP_C = "01";// # 네이버: 01, 카카오: 02
|
||||
var SNS_ATTC_KEY = 59711004
|
||||
let successfulCalls = 0;
|
||||
let failedCalls = 0;
|
||||
console.log(`[테스트 시작] 총 ${totalCalls}회 순차 호출 (매 1초 간격)`);
|
||||
for (let i = 0; i <= totalCalls; i++) {
|
||||
const startTime = performance.now(); // 요청 시작 시간
|
||||
var data = data = {
|
||||
"CERT_PURPOSE": "",
|
||||
"SNS_TP_C": SNS_TP_C,
|
||||
"SNS_ATTC_KEY": SNS_ATTC_KEY + i,
|
||||
"RQR_PATH_C": "03",
|
||||
"AP_AUT_LGIN_YN": "N",
|
||||
"TRM_NATV_ID": "98330320250312105723",
|
||||
"PRL_CHAN_C": "",
|
||||
"TRM_OS_C": "01",
|
||||
"OPI_CI": "MEMBERS",
|
||||
"OPI_RRRC": "",
|
||||
"OPI_RRRD": "",
|
||||
"OPI_EXPIRE_TIME": "",
|
||||
"OPI_ACCESS_TOKEN": "",
|
||||
"OPI_DEVICE_ID": "",
|
||||
"OPI_RESULT_CODE": "",
|
||||
"ANW_AP_PUSH_YN": "Y",
|
||||
"OPI_JOIN_YN": "",
|
||||
"AD_ID": "fd42945f-3d3d-485a-8a33-e6ac40eae597",
|
||||
"isLoginPage": "Y"
|
||||
}
|
||||
try {
|
||||
// 1. fetch 요청을 보내고 완료될 때까지 기다립니다.
|
||||
const response = await fetch("https://m.nhmembers.co.kr/nhpot/login/snsLoginCertNew.ajax", {
|
||||
"headers": {
|
||||
"User-Agent" : "NH_MEMBERS_ANDROID2.0.021",
|
||||
},
|
||||
"body": data,
|
||||
"method": "POST",
|
||||
});
|
||||
|
||||
const duration = (performance.now() - startTime).toFixed(2); // 응답 시간
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const {resultCode , resultMessage} = await response.json();
|
||||
console.log(`[${i}/${totalCalls}회] ✅ 성공 (상태: ${response.status}, ${duration}ms) SNS_ATT:${SNS_ATTC_KEY + i} ${resultCode} : ${resultMessage}`);
|
||||
if (resultCode !== '9999') {
|
||||
successfulCalls++;
|
||||
} else {
|
||||
failedCalls++;
|
||||
}
|
||||
} catch (error) {
|
||||
// 3. 네트워크 오류 또는 fetch 실패 시 처리
|
||||
const duration = (performance.now() - startTime).toFixed(2);
|
||||
console.error(`[${i}/${totalCalls}회] ❌ 실패 (${error.message}, ${duration}ms)`);
|
||||
failedCalls++;
|
||||
}
|
||||
|
||||
// 4. 마지막 호출이 아닐 경우, 1초간 대기합니다.
|
||||
if (i < totalCalls) {
|
||||
await delay(50); // 1000ms = 1초
|
||||
}
|
||||
}
|
||||
|
||||
console.log('--------------------');
|
||||
console.log('[로그인 테스트 완료]');
|
||||
console.log(`성공: ${successfulCalls}회`);
|
||||
console.log(`실패: ${failedCalls}회`);
|
||||
console.log('--------------------');
|
||||
|
||||
|
||||
try {
|
||||
hybridaction.action('{"package": "com.nh.android.nhmembers.plugin","class": "HPPreference", "action": "get", "request_id": "testrequest", "callback": "document.write", "argument": {"key": "__TOKEN_DATA__"}}')
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
testCall(1000);
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"data" : {
|
||||
"type" : "appStoreVersions",
|
||||
"id" : "d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b",
|
||||
"attributes" : {
|
||||
"platform" : "IOS",
|
||||
"versionString" : "2.2.1",
|
||||
"appStoreState" : "READY_FOR_SALE",
|
||||
"appVersionState" : "READY_FOR_DISTRIBUTION",
|
||||
"copyright" : "2018 NH Information System CO.LTD",
|
||||
"reviewType" : "APP_STORE",
|
||||
"releaseType" : "MANUAL",
|
||||
"earliestReleaseDate" : null,
|
||||
"usesIdfa" : null,
|
||||
"downloadable" : true,
|
||||
"createdDate" : "2025-06-24T03:39:38-07:00"
|
||||
},
|
||||
"relationships" : {
|
||||
"ageRatingDeclaration" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/ageRatingDeclaration",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/ageRatingDeclaration"
|
||||
}
|
||||
},
|
||||
"appStoreVersionLocalizations" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreVersionLocalizations",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreVersionLocalizations"
|
||||
}
|
||||
},
|
||||
"build" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/build",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/build"
|
||||
}
|
||||
},
|
||||
"appStoreVersionPhasedRelease" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreVersionPhasedRelease",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreVersionPhasedRelease"
|
||||
}
|
||||
},
|
||||
"gameCenterAppVersion" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/gameCenterAppVersion",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/gameCenterAppVersion"
|
||||
}
|
||||
},
|
||||
"routingAppCoverage" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/routingAppCoverage",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/routingAppCoverage"
|
||||
}
|
||||
},
|
||||
"appStoreReviewDetail" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreReviewDetail",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreReviewDetail"
|
||||
}
|
||||
},
|
||||
"appStoreVersionSubmission" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreVersionSubmission",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreVersionSubmission"
|
||||
}
|
||||
},
|
||||
"appClipDefaultExperience" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appClipDefaultExperience",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appClipDefaultExperience"
|
||||
}
|
||||
},
|
||||
"appStoreVersionExperiments" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreVersionExperiments",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreVersionExperiments"
|
||||
}
|
||||
},
|
||||
"appStoreVersionExperimentsV2" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/appStoreVersionExperimentsV2",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/appStoreVersionExperimentsV2"
|
||||
}
|
||||
},
|
||||
"customerReviews" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/customerReviews",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/customerReviews"
|
||||
}
|
||||
},
|
||||
"alternativeDistributionPackage" : {
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/relationships/alternativeDistributionPackage",
|
||||
"related" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b/alternativeDistributionPackage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b"
|
||||
}
|
||||
},
|
||||
"links" : {
|
||||
"self" : "https://api.appstoreconnect.apple.com/v1/appStoreVersions/d5d8c453-40e8-49be-ba7e-ca9ef06bdb8b"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
(function() {
|
||||
console.log("Enhanced Scroll & Click Loop Started");
|
||||
|
||||
const CLICK_INTERVAL = 1000;
|
||||
const SCROLL_STEP = 300;
|
||||
|
||||
const selectors = [
|
||||
'a', 'button', 'a.btn', 'input[type="button"]',
|
||||
'input[type="submit"]', '[role="button"]'
|
||||
];
|
||||
|
||||
// --- 설정 구역 ---
|
||||
const config = {
|
||||
// 1. 특정 페이지에서 순서대로 클릭해야 하는 경우
|
||||
sequences: {
|
||||
"www.nhmembers.co.kr/nhaob": [".btn-direct-menu"],
|
||||
"example.com/login": [".userid-input", ".password-input", "#login-btn"],
|
||||
"mysite.com/survey": ["input[value='yes']", "button.next-step"]
|
||||
},
|
||||
// 2. 특정 페이지에서 절대 클릭하면 안 되는 요소 (예: 로그아웃, 삭제 버튼)
|
||||
blacklist: {
|
||||
"any": ["logout", "delete", "remove", "exit","header__prev main_header"], // 모든 페이지 공통 키워드
|
||||
"runcomm.co.kr": [".adpot_inquiry", ",btn_com1", "닫기"] // 특정 페이지 전용
|
||||
}
|
||||
};
|
||||
|
||||
let sequenceStep = 0;
|
||||
let lastUrl = "";
|
||||
|
||||
const mainLoop = setInterval(() => {
|
||||
const currentUrl = window.location.href;
|
||||
|
||||
// 페이지가 바뀌면 순서(Step) 초기화
|
||||
if (currentUrl !== lastUrl) {
|
||||
sequenceStep = 0;
|
||||
lastUrl = currentUrl;
|
||||
}
|
||||
|
||||
// --- 로직 1: 특정 주소에서의 순차 클릭 처리 ---
|
||||
const activeSequenceKey = Object.keys(config.sequences).find(url => currentUrl.includes(url));
|
||||
|
||||
if (activeSequenceKey) {
|
||||
const steps = config.sequences[activeSequenceKey];
|
||||
if (sequenceStep < steps.length) {
|
||||
const targetSelector = steps[sequenceStep];
|
||||
const target = document.querySelector(targetSelector);
|
||||
|
||||
if (target && isVisible(target)) {
|
||||
console.log(`[Sequence] Clicking step ` + sequenceStep + ' : ', targetSelector);
|
||||
target.click();
|
||||
sequenceStep++; // 다음 단계로
|
||||
return; // 순차 클릭을 했을 경우 랜덤 클릭 건너뜀
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 로직 2: 일반 랜덤 클릭 (예외 처리 포함) ---
|
||||
window.scrollBy(0, SCROLL_STEP);
|
||||
|
||||
const elements = document.querySelectorAll(selectors.join(','));
|
||||
const visibleElements = Array.from(elements).filter(el => {
|
||||
if (!isVisible(el)) return false;
|
||||
|
||||
// 현재 페이지에 적용할 블랙리스트 단어들 모으기
|
||||
const pageBlacklist = config.blacklist["any"].concat(
|
||||
Object.entries(config.blacklist)
|
||||
.filter(([url]) => currentUrl.includes(url))
|
||||
.flatMap(([_, tags]) => tags)
|
||||
);
|
||||
|
||||
// 검사할 대상 문자열들을 배열로 만듦
|
||||
const targetsToScan = [
|
||||
el.innerText, // 버튼 위 텍스트
|
||||
el.id, // ID
|
||||
el.className.toString(), // 클래스명
|
||||
el.getAttribute('alt'), // 이미지 대체 텍스트 (중요!)
|
||||
el.getAttribute('title'), // 마우스 올리면 나오는 텍스트
|
||||
el.getAttribute('aria-label') // 웹 접근성용 라벨
|
||||
].map(val => (val || "").toLowerCase()); // 소문자로 통일해서 비교
|
||||
|
||||
// 블랙리스트 단어가 위 항목 중 하나라도 포함되어 있는지 확인
|
||||
const isBlacklisted = pageBlacklist.some(term =>
|
||||
targetsToScan.some(content => content.includes(term.toLowerCase()))
|
||||
);
|
||||
|
||||
return !isBlacklisted;
|
||||
});
|
||||
|
||||
if (visibleElements.length > 0) {
|
||||
const randomIndex = Math.floor(Math.random() * visibleElements.length);
|
||||
const target = visibleElements[randomIndex];
|
||||
console.log('Target Clicked:', target.innerText || target.tagName);
|
||||
try { target.click(); } catch (e) { console.error(e); }
|
||||
}
|
||||
|
||||
if ((window.innerHeight + window.pageYOffset) >= document.documentElement.scrollHeight) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
}, CLICK_INTERVAL);
|
||||
|
||||
// 가시성 확인 함수
|
||||
function isVisible(el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.width > 0 && rect.height > 0 &&
|
||||
rect.top >= 0 && rect.top <= window.innerHeight &&
|
||||
window.getComputedStyle(el).visibility !== 'hidden' &&
|
||||
window.getComputedStyle(el).display !== 'none';
|
||||
}
|
||||
|
||||
window.autoCrawlerLoop = mainLoop;
|
||||
})();
|
||||
|
||||
|
||||
window.addEventListener('error', function(event) {
|
||||
// 1. 일반적인 JS 문법/런타임 에러
|
||||
if (event.message) {
|
||||
const errorLog = {
|
||||
type: 'JS_ERROR,
|
||||
message: event.message,
|
||||
source: event.filename,
|
||||
line: event.lineno
|
||||
};
|
||||
console.warn(`Error: ` + event.message);
|
||||
}
|
||||
// 2. 리소스 로드 에러 (이미지, JS 파일이 없을 때)
|
||||
else {
|
||||
const target = event.target || event.srcElement;
|
||||
console.warn('Resource Load Error:', target.src || target.href);
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
function kkk(){
|
||||
var sss = document.getElementsByTagName('meta');
|
||||
for(i=0;i<sss.length;i++) {
|
||||
if(sss[i].name.includes("viewport")) {
|
||||
console.log(sss[i]);
|
||||
sss[i].remove();
|
||||
}
|
||||
}
|
||||
|
||||
var meta = document.createElement('meta'); meta.setAttribute( 'name', 'viewport' ); meta.setAttribute( 'content', 'width = device-width, initial-scale = 1.0, minimum-scale = 1.0, maximum-scale = 4.0, user-scalable = yes, viewport-fit=cover' );
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
var meta = document.createElement('meta'); meta.setAttribute( 'name', 'viewport' ); meta.setAttribute( 'content', 'width = device-width, initial-scale = 1.0, minimum-scale = 1.0, maximum-scale = 4.0, user-scalable = yes, viewport-fit=cover' );
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
}
|
||||
|
||||
let scale = 1.0; // 현재 확대 비율
|
||||
let startDistance = 0; // 터치 시작 시점의 두 손가락 거리
|
||||
let baseScale = 1.0; // 터치 시작 시점의 기존 확대 비율
|
||||
|
||||
// 두 손가락 사이의 거리를 계산하는 함수 (피타고라스 정리 활용)
|
||||
function getDistance(touch1, touch2) {
|
||||
const dx = touch1.clientX - touch2.clientX;
|
||||
const dy = touch1.clientY - touch2.clientY;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
const target = document.body;
|
||||
|
||||
// transform이 일어날 기준점을 왼쪽 상단(0,0)으로 고정
|
||||
target.style.transformOrigin = "0 0";
|
||||
target.style.transition = "transform 0.05s ease-out"; // 부드러운 애니메이션 효과
|
||||
|
||||
// 1. 터치 시작 (두 손가락이 닿았을 때)
|
||||
window.addEventListener('touchstart', (e) => {
|
||||
if (e.touches.length === 2) {
|
||||
// 기본 브라우저 줌인 동작 방지
|
||||
e.preventDefault();
|
||||
|
||||
startDistance = getDistance(e.touches[0], e.touches[1]);
|
||||
baseScale = scale; // 현재 배율을 기준으로 저장
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
// 2. 터치 이동 (손가락을 벌리거나 오므릴 때)
|
||||
window.addEventListener('touchmove', (e) => {
|
||||
if (e.touches.length === 2) {
|
||||
e.preventDefault();
|
||||
|
||||
const currentDistance = getDistance(e.touches[0], e.touches[1]);
|
||||
if (startDistance > 0) {
|
||||
// 거리 비율만큼 배율 계산
|
||||
const distanceRatio = currentDistance / startDistance;
|
||||
let newScale = baseScale * distanceRatio;
|
||||
|
||||
// 최소 1배 ~ 최대 3배까지만 확대 제한 (원하는 대로 조절 가능)
|
||||
newScale = Math.max(1.0, Math.min(newScale, 3.0));
|
||||
|
||||
scale = newScale;
|
||||
target.style.transform = `scale(${scale})`;
|
||||
console.log('Scale: ', + target.style.transform);
|
||||
}
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
// 3. 터치 종료 (손가락을 뗐을 때)
|
||||
window.addEventListener('touchend', (e) => {
|
||||
if (e.touches.length < 2) {
|
||||
startDistance = 0; // 거리 초기화
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,305 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Config Generator</title>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background: #f4f7f8; padding: 20px; color: #333; }
|
||||
.container { max-width: 900px; margin: 0 auto; }
|
||||
h1, h2 { color: #2c3e50; }
|
||||
.card { background: #fff; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
|
||||
/* Drag & Drop 영역 */
|
||||
.drop-zone { border: 2px dashed #3498db; border-radius: 8px; padding: 30px; text-align: center; background: #ebf5fb; color: #2980b9; font-weight: bold; cursor: pointer; transition: background 0.3s; margin-bottom: 20px; }
|
||||
.drop-zone.dragover { background: #d6eaf8; border-color: #2980b9; }
|
||||
|
||||
.url-block { border: 1px solid #e1e8ed; padding: 15px; border-radius: 6px; margin-bottom: 15px; position: relative; background: #fafbfc; }
|
||||
.remove-btn { position: absolute; right: 15px; top: 15px; background: #ff4757; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; }
|
||||
|
||||
.step-block { display: flex; gap: 10px; align-items: flex-start; background: #fff; border: 1px dashed #ccc; padding: 10px; border-radius: 4px; margin-top: 10px; }
|
||||
.step-block select, .step-block input, .step-block textarea { padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; }
|
||||
.step-block .code-input { flex-grow: 1; }
|
||||
.step-block textarea { width: 100%; height: 60px; font-family: monospace; resize: vertical; }
|
||||
.step-block .wait-input { width: 100px; }
|
||||
|
||||
.btn { background: #2ed573; color: white; border: none; padding: 8px 15px; border-radius: 4px; cursor: pointer; font-weight: bold; margin-top: 10px; }
|
||||
.btn-add { background: #1e90ff; }
|
||||
.btn-generate { background: #3742fa; font-size: 16px; padding: 12px 20px; width: 48%; }
|
||||
.btn-export { background: #f39c12; font-size: 16px; padding: 12px 20px; width: 48%; float: right; }
|
||||
|
||||
input[type="text"] { width: 300px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; }
|
||||
|
||||
pre { background: #2f3542; color: #f1f2f6; padding: 20px; border-radius: 8px; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; }
|
||||
.btn-row { display: flex; justify-content: space-between; margin-top: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h1>봇 설정(Config) 생성기</h1>
|
||||
|
||||
<div id="dropZone" class="drop-zone">
|
||||
📂 여기에 JSON 백업 파일을 드래그하거나 클릭하여 불러오세요.
|
||||
<input type="file" id="fileInput" accept=".json" style="display: none;">
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>1. Sequences (순차 처리)</h2>
|
||||
<div id="sequences-container"></div>
|
||||
<button class="btn btn-add" onclick="addSequenceUrl()">+ URL 추가</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>2. Blacklist (클릭 제외)</h2>
|
||||
<div id="blacklist-container"></div>
|
||||
<button class="btn btn-add" onclick="addBlacklistUrl()">+ 블랙리스트 URL 추가</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-generate" onclick="generateCode()">🚀 JS 코드 생성하기</button>
|
||||
<button class="btn btn-export" onclick="exportJson()">💾 프로젝트 JSON 저장</button>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: 20px;">
|
||||
<h2>결과 코드 (앱 삽입용)</h2>
|
||||
<pre><code id="outputCode">// 여기에 자바스크립트 코드가 생성됩니다.</code></pre>
|
||||
<button class="btn" onclick="copyCode()">코드 복사하기</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let sequenceCounter = 0;
|
||||
let stepCounter = 0;
|
||||
let blacklistCounter = 0;
|
||||
|
||||
// --- 초기 샘플 데이터 ---
|
||||
const sampleData = {
|
||||
sequences: {
|
||||
"multicon.co.kr/couponMall/order/info": [
|
||||
{ type: "target", value: "document.querySelector('.point_inquiry').click()", wait: "5000" },
|
||||
{ type: "action", value: 'if(document.querySelector(".result_point").innerText.split("P")[0] > 0) {\n location.href = "${NH_DOMAIN + APP_LOG}";\n}', wait: "15000" }
|
||||
]
|
||||
},
|
||||
blacklist: {
|
||||
"any": ["logout", "delete", "remove", "exit", "header__prev main_header"],
|
||||
"runcomm.co.kr": [".adpot_inquiry", ",btn_com1", "닫기"]
|
||||
}
|
||||
};
|
||||
|
||||
// --- DOM 생성 로직 ---
|
||||
function addSequenceUrl(url = '') {
|
||||
const id = sequenceCounter++;
|
||||
const container = document.getElementById('sequences-container');
|
||||
const html = `
|
||||
<div class="url-block" id="seq-${id}">
|
||||
<button class="remove-btn" onclick="document.getElementById('seq-${id}').remove()">삭제</button>
|
||||
<label><strong>URL 키워드:</strong></label>
|
||||
<input type="text" class="seq-url" placeholder="예: example.com/login" value="${url}">
|
||||
<div id="steps-container-${id}" style="margin-top: 15px;"></div>
|
||||
<button class="btn btn-add" style="background:#57606f;" onclick="addStep(${id})">+ 스텝(Step) 추가</button>
|
||||
</div>
|
||||
`;
|
||||
container.insertAdjacentHTML('beforeend', html);
|
||||
return id;
|
||||
}
|
||||
|
||||
function addStep(urlId, stepData = { type: 'string', value: '', wait: '' }) {
|
||||
const sId = stepCounter++;
|
||||
const container = document.getElementById(`steps-container-${urlId}`);
|
||||
const html = `
|
||||
<div class="step-block" id="step-${sId}">
|
||||
<select class="step-type" onchange="changeStepType(${sId})">
|
||||
<option value="string" ${stepData.type === 'string' ? 'selected' : ''}>기본 클릭 (문자열)</option>
|
||||
<option value="target" ${stepData.type === 'target' ? 'selected' : ''}>동적 타겟 (Target)</option>
|
||||
<option value="action" ${stepData.type === 'action' ? 'selected' : ''}>순수 함수 (Action)</option>
|
||||
</select>
|
||||
<div id="step-input-area-${sId}" style="flex-grow: 1; display: flex; gap: 10px;"></div>
|
||||
<button class="remove-btn" style="position:static;" onclick="document.getElementById('step-${sId}').remove()">X</button>
|
||||
</div>
|
||||
`;
|
||||
container.insertAdjacentHTML('beforeend', html);
|
||||
|
||||
changeStepType(sId, stepData.value, stepData.wait);
|
||||
}
|
||||
|
||||
function changeStepType(sId, defaultValue = '', defaultWait = '') {
|
||||
const type = document.querySelector(`#step-${sId} .step-type`).value;
|
||||
const area = document.getElementById(`step-input-area-${sId}`);
|
||||
|
||||
// 기존 값이 있다면 보존, 없다면 인자값 사용
|
||||
const existingInput = area.querySelector('.seq-val');
|
||||
const existingWait = area.querySelector('.wait-input');
|
||||
const val = existingInput ? existingInput.value : defaultValue;
|
||||
const wait = existingWait ? existingWait.value : defaultWait;
|
||||
|
||||
if (type === 'string') {
|
||||
area.innerHTML = `<input type="text" class="code-input seq-val" placeholder='CSS 선택자 (예: .btn-login)' value="${val}">`;
|
||||
} else if (type === 'target') {
|
||||
area.innerHTML = `
|
||||
<div style="flex-grow:1;">
|
||||
<span style="font-family:monospace; font-size:12px;">() => </span>
|
||||
<input type="text" class="code-input seq-val" style="width: calc(100% - 40px);" placeholder="document.querySelector('.btn')" value="${val}">
|
||||
</div>
|
||||
<input type="number" class="wait-input" placeholder="Wait(ms)" value="${wait}">
|
||||
`;
|
||||
} else if (type === 'action') {
|
||||
area.innerHTML = `
|
||||
<textarea class="code-input seq-val" placeholder="if(condition) { location.href='...'; }">${val}</textarea>
|
||||
<input type="number" class="wait-input" placeholder="Wait(ms)" value="${wait}">
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function addBlacklistUrl(url = '', tagsArray = []) {
|
||||
const id = blacklistCounter++;
|
||||
const container = document.getElementById('blacklist-container');
|
||||
const tags = tagsArray.join(', ');
|
||||
const html = `
|
||||
<div class="url-block" id="bl-${id}">
|
||||
<button class="remove-btn" onclick="document.getElementById('bl-${id}').remove()">삭제</button>
|
||||
<label><strong>URL 키워드:</strong></label>
|
||||
<input type="text" class="bl-url" placeholder="예: any 또는 특정 URL" value="${url}">
|
||||
<div style="margin-top: 10px;">
|
||||
<label><strong>제외 키워드:</strong> (콤마 ',' 로 구분)</label><br>
|
||||
<input type="text" class="bl-tags" style="width: 100%; margin-top:5px;" placeholder="logout, delete" value="${tags}">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
|
||||
// --- JSON Load & Export 로직 ---
|
||||
function loadFromJson(data) {
|
||||
document.getElementById('sequences-container').innerHTML = '';
|
||||
document.getElementById('blacklist-container').innerHTML = '';
|
||||
|
||||
if (data.sequences) {
|
||||
for (const [url, steps] of Object.entries(data.sequences)) {
|
||||
const urlId = addSequenceUrl(url);
|
||||
steps.forEach(step => addStep(urlId, step));
|
||||
}
|
||||
}
|
||||
if (data.blacklist) {
|
||||
for (const [url, tags] of Object.entries(data.blacklist)) {
|
||||
addBlacklistUrl(url, tags);
|
||||
}
|
||||
}
|
||||
generateCode();
|
||||
}
|
||||
|
||||
function extractCurrentData() {
|
||||
const data = { sequences: {}, blacklist: {} };
|
||||
|
||||
document.querySelectorAll('[id^="seq-"]').forEach(urlBlock => {
|
||||
const url = urlBlock.querySelector('.seq-url').value.trim();
|
||||
if (!url) return;
|
||||
data.sequences[url] = [];
|
||||
|
||||
urlBlock.querySelectorAll('.step-block').forEach(stepBlock => {
|
||||
const type = stepBlock.querySelector('.step-type').value;
|
||||
const val = stepBlock.querySelector('.seq-val').value.trim();
|
||||
const waitInput = stepBlock.querySelector('.wait-input');
|
||||
const wait = waitInput && waitInput.value ? waitInput.value : "";
|
||||
|
||||
if (val) data.sequences[url].push({ type, value: val, wait });
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('[id^="bl-"]').forEach(blBlock => {
|
||||
const url = blBlock.querySelector('.bl-url').value.trim();
|
||||
const tags = blBlock.querySelector('.bl-tags').value.split(',').map(t => t.trim()).filter(t => t);
|
||||
if (url && tags.length > 0) data.blacklist[url] = tags;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function exportJson() {
|
||||
const data = extractCurrentData();
|
||||
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data, null, 2));
|
||||
const downloadAnchorNode = document.createElement('a');
|
||||
downloadAnchorNode.setAttribute("href", dataStr);
|
||||
downloadAnchorNode.setAttribute("download", "config_project.json");
|
||||
document.body.appendChild(downloadAnchorNode);
|
||||
downloadAnchorNode.click();
|
||||
downloadAnchorNode.remove();
|
||||
}
|
||||
|
||||
// --- 자바스크립트 코드(앱용) 생성 로직 ---
|
||||
function generateCode() {
|
||||
const data = extractCurrentData();
|
||||
let code = "const config = {\n sequences: {\n";
|
||||
|
||||
for (const [url, steps] of Object.entries(data.sequences)) {
|
||||
code += ` "${url}": [\n`;
|
||||
steps.forEach(step => {
|
||||
const waitStr = step.wait ? `, wait: ${step.wait}` : '';
|
||||
if (step.type === 'string') {
|
||||
code += ` "${step.value}",\n`;
|
||||
} else if (step.type === 'target') {
|
||||
code += ` { target: () => ${step.value}${waitStr} },\n`;
|
||||
} else if (step.type === 'action') {
|
||||
const formattedVal = step.value.includes('\n') ? `\n ${step.value.replace(/\n/g, '\n ')}\n ` : step.value;
|
||||
code += ` { action: () => { ${formattedVal} }${waitStr} },\n`;
|
||||
}
|
||||
});
|
||||
code += ` ],\n`;
|
||||
}
|
||||
|
||||
code += " },\n blacklist: {\n";
|
||||
for (const [url, tags] of Object.entries(data.blacklist)) {
|
||||
const tagsStr = tags.map(t => `"${t}"`).join(', ');
|
||||
code += ` "${url}": [${tagsStr}],\n`;
|
||||
}
|
||||
code += " }\n};";
|
||||
|
||||
document.getElementById('outputCode').textContent = code;
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
const text = document.getElementById('outputCode').textContent;
|
||||
navigator.clipboard.writeText(text).then(() => alert('코드가 복사되었습니다!'));
|
||||
}
|
||||
|
||||
// --- Drag & Drop 파일 업로드 로직 ---
|
||||
const dropZone = document.getElementById('dropZone');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
|
||||
dropZone.addEventListener('click', () => fileInput.click());
|
||||
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('dragover'); });
|
||||
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover'));
|
||||
dropZone.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
dropZone.classList.remove('dragover');
|
||||
if (e.dataTransfer.files.length) handleFile(e.dataTransfer.files[0]);
|
||||
});
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
if (e.target.files.length) handleFile(e.target.files[0]);
|
||||
});
|
||||
|
||||
function handleFile(file) {
|
||||
if (!file.name.endsWith('.json')) {
|
||||
alert('JSON 파일만 업로드 가능합니다.');
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const json = JSON.parse(e.target.result);
|
||||
loadFromJson(json);
|
||||
alert('데이터를 성공적으로 불러왔습니다.');
|
||||
} catch (err) {
|
||||
alert('JSON 파싱에 실패했습니다: ' + err.message);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
// --- 초기 실행 ---
|
||||
window.onload = () => {
|
||||
loadFromJson(sampleData);
|
||||
};
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+13
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,297 @@
|
||||
#include "AnimationStrategy.h"
|
||||
#include "Renderer.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
|
||||
// ====================================================================
|
||||
// --- PAN (왕복 이동) 애니메이션 ---
|
||||
// ====================================================================
|
||||
class PanAnimation : public AnimationStrategy {
|
||||
public:
|
||||
PanAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||
|
||||
void reset() override {
|
||||
state_.offsetX = 0.0f; state_.offsetY = 0.0f;
|
||||
state_.scale = 1.0f; cycleComplete_ = false;
|
||||
xDirection_ = -1; // 시작 방향을 -1 (좌로 이동)으로 변경
|
||||
yDirection_ = -1; // 시작 방향을 -1 (위로 이동)으로 변경
|
||||
}
|
||||
AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
AnimationState startState;
|
||||
startState.offsetX = 0.0f;
|
||||
startState.offsetY = 0.0f;
|
||||
startState.scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||
return startState;
|
||||
}
|
||||
|
||||
AnimationState getState() const override { return state_; }
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
bool cycleComplete = false;
|
||||
|
||||
float overflowX = 0.0f, overflowY = 0.0f;
|
||||
float scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||
state_.scale = scale; // 마지막 상태 저장을 위해 현재 스케일값 기록
|
||||
float mediaW = static_cast<float>(media.getWidth());
|
||||
float mediaH = static_cast<float>(media.getHeight());
|
||||
if ((mediaW / mediaH) > ((float)surfaceWidth / surfaceHeight)) {
|
||||
overflowX = std::max(0.0f, mediaW * scale - surfaceWidth);
|
||||
} else {
|
||||
overflowY = std::max(0.0f, mediaH * scale - surfaceHeight);
|
||||
}
|
||||
|
||||
if (!cycleComplete_) {
|
||||
bool xDone = (overflowX <= 0);
|
||||
bool yDone = (overflowY <= 0);
|
||||
if (overflowX > 0) {
|
||||
// offsetX를 음수 방향으로 움직임 (0 -> -overflowX)
|
||||
state_.offsetX += animationSpeed_ * xDirection_;
|
||||
if (xDirection_ == -1 && state_.offsetX <= -overflowX) { state_.offsetX = -overflowX; xDirection_ = 1; }
|
||||
else if (xDirection_ == 1 && state_.offsetX >= 0) { state_.offsetX = 0; xDirection_ = -1; xDone = true; }
|
||||
}
|
||||
if (overflowY > 0) {
|
||||
// offsetY를 음수 방향으로 움직임 (0 -> -overflowY)
|
||||
state_.offsetY += animationSpeed_ * yDirection_;
|
||||
if (yDirection_ == -1 && state_.offsetY <= -overflowY) { state_.offsetY = -overflowY; yDirection_ = 1; }
|
||||
else if (yDirection_ == 1 && state_.offsetY >= 0) { state_.offsetY = 0; yDirection_ = -1; yDone = true; }
|
||||
}
|
||||
if (xDone && yDone) cycleComplete_ = true;
|
||||
}
|
||||
|
||||
renderer->drawMedia(buffer, media, 1.0f, state_.offsetX, state_.offsetY, state_.scale);
|
||||
return cycleComplete_;
|
||||
}
|
||||
|
||||
private:
|
||||
AnimationState state_;
|
||||
int xDirection_, yDirection_;
|
||||
bool cycleComplete_;
|
||||
|
||||
float getBaseScale(MediaAsset& media, int surfaceWidth, int surfaceHeight) {
|
||||
if (media.getHeight() == 0 || surfaceHeight == 0) return 1.0f;
|
||||
float scale;
|
||||
if ((static_cast<float>(media.getWidth()) / media.getHeight()) > ((float)surfaceWidth / surfaceHeight)) {
|
||||
scale = (float)surfaceHeight / media.getHeight();
|
||||
} else {
|
||||
scale = (float)surfaceWidth / media.getWidth();
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- PAN_ONE_WAY (편도 이동) 애니메이션 ---
|
||||
// ====================================================================
|
||||
class PanOneWayAnimation : public AnimationStrategy {
|
||||
public:
|
||||
PanOneWayAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||
void reset() override { state_ = AnimationState(); cycleComplete_ = false; }
|
||||
AnimationState getState() const override { return state_; }
|
||||
|
||||
AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
AnimationState startState;
|
||||
startState.offsetX = 0.0f;
|
||||
startState.offsetY = 0.0f;
|
||||
startState.scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||
return startState;
|
||||
}
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
float overflowX = 0.0f, overflowY = 0.0f;
|
||||
float scale = getBaseScale(media, surfaceWidth, surfaceHeight);
|
||||
state_.scale = scale;
|
||||
float mediaW = static_cast<float>(media.getWidth());
|
||||
float mediaH = static_cast<float>(media.getHeight());
|
||||
if ((mediaW / mediaH) > ((float)surfaceWidth / surfaceHeight)) {
|
||||
overflowX = std::max(0.0f, mediaW * scale - surfaceWidth);
|
||||
} else {
|
||||
overflowY = std::max(0.0f, mediaH * scale - surfaceHeight);
|
||||
}
|
||||
if (!cycleComplete_) {
|
||||
bool xReachedEnd = (overflowX <= 0);
|
||||
bool yReachedEnd = (overflowY <= 0);
|
||||
if (overflowX > 0) {
|
||||
// offsetX를 음수 방향으로만 이동
|
||||
state_.offsetX -= animationSpeed_;
|
||||
if (state_.offsetX <= -overflowX) { state_.offsetX = -overflowX; xReachedEnd = true; }
|
||||
}
|
||||
if (overflowY > 0) {
|
||||
// offsetY를 음수 방향으로만 이동
|
||||
state_.offsetY -= animationSpeed_;
|
||||
if (state_.offsetY <= -overflowY) { state_.offsetY = -overflowY; yReachedEnd = true; }
|
||||
}
|
||||
if (xReachedEnd && yReachedEnd) cycleComplete_ = true;
|
||||
}
|
||||
|
||||
renderer->drawMedia(buffer, media, 1.0f, state_.offsetX, state_.offsetY, state_.scale);
|
||||
return cycleComplete_;
|
||||
}
|
||||
private:
|
||||
AnimationState state_;
|
||||
bool cycleComplete_;
|
||||
float getBaseScale(MediaAsset& media, int surfaceWidth, int surfaceHeight) { /* PanAnimation과 동일 */
|
||||
if (media.getHeight() == 0 || surfaceHeight == 0) return 1.0f;
|
||||
float scale;
|
||||
if ((static_cast<float>(media.getWidth()) / media.getHeight()) > ((float)surfaceWidth / surfaceHeight)) {
|
||||
scale = (float)surfaceHeight / media.getHeight();
|
||||
} else {
|
||||
scale = (float)surfaceWidth / media.getWidth();
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- ZOOM 애니메이션 (수정) ---
|
||||
// ====================================================================
|
||||
class ZoomAnimation : public AnimationStrategy {
|
||||
public:
|
||||
ZoomAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||
|
||||
void reset() override {
|
||||
state_ = AnimationState();
|
||||
zoomMultiplier_ = 1.0f; // 줌 배율은 1.0에서 시작
|
||||
cycleComplete_ = false;
|
||||
zoomDirection_ = 1;
|
||||
}
|
||||
const float zoom_max = 1.35f;
|
||||
AnimationState getState() const override { return state_; }
|
||||
|
||||
AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
AnimationState startState;
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
startState.offsetX = baseOffsetX;
|
||||
startState.offsetY = baseOffsetY;
|
||||
startState.scale = baseScale * 1.0f; // Zoom의 시작 배율은 1.0
|
||||
return startState;
|
||||
}
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
if (!cycleComplete_) {
|
||||
// 줌 배율만 업데이트 (1.0 ~ 1.2)
|
||||
zoomMultiplier_ += 0.0004f * animationSpeed_ * zoomDirection_;
|
||||
if (zoomDirection_ == 1 && zoomMultiplier_ >= zoom_max) {
|
||||
zoomDirection_ = -1;
|
||||
} else if (zoomMultiplier_ <= 1.0 && zoomDirection_ == -1){
|
||||
cycleComplete_ = true; // 최대 확대 시 사이클 완료
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 화면에 꽉 차는 기본 스케일을 계산
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
|
||||
// 2. 최종 스케일은 기본 스케일 * 애니메이션 줌 배율
|
||||
float finalScale = baseScale * zoomMultiplier_;
|
||||
|
||||
// 3. ***변경된 최종 스케일을 바탕으로*** 중앙 정렬 오프셋을 새로 계산
|
||||
float finalOffsetX = (static_cast<float>(surfaceWidth) - (media.getWidth() * finalScale)) / 2.0f;
|
||||
float finalOffsetY = (static_cast<float>(surfaceHeight) - (media.getHeight() * finalScale)) / 2.0f;
|
||||
|
||||
// 4. getState()가 올바른 마지막 상태를 보고할 수 있도록 state_에 최종 상태 저장
|
||||
state_.offsetX = finalOffsetX;
|
||||
state_.offsetY = finalOffsetY;
|
||||
state_.scale = finalScale;
|
||||
|
||||
// 5. 최종 계산된 값으로 그리기
|
||||
renderer->drawMedia(buffer, media, 1.0f, state_.offsetX, state_.offsetY, state_.scale);
|
||||
|
||||
return cycleComplete_;
|
||||
}
|
||||
|
||||
private:
|
||||
AnimationState state_;
|
||||
float zoomMultiplier_; // 애니메이션 배율만 따로 관리
|
||||
int zoomDirection_;
|
||||
bool cycleComplete_;
|
||||
};
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- PAGE_TURN (대기) 애니메이션 ---
|
||||
// ====================================================================
|
||||
class PageTurnAnimation : public AnimationStrategy {
|
||||
public:
|
||||
PageTurnAnimation(float speed, long long delay) : AnimationStrategy(speed), delayMs_(delay) { reset(); }
|
||||
|
||||
void reset() override {
|
||||
state_ = AnimationState();
|
||||
cycleComplete_ = false;
|
||||
startTime_ = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
AnimationState startState;
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
startState.offsetX = baseOffsetX;
|
||||
startState.offsetY = baseOffsetY;
|
||||
startState.scale = baseScale * 1.0f; // Zoom의 시작 배율은 1.0
|
||||
return startState;
|
||||
}
|
||||
|
||||
AnimationState getState() const override { return state_; }
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
if (!cycleComplete_) {
|
||||
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime_).count();
|
||||
if (elapsed >= delayMs_) {
|
||||
cycleComplete_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
state_.offsetX = baseOffsetX;
|
||||
state_.offsetY = baseOffsetY;
|
||||
state_.scale = baseScale;
|
||||
renderer->drawMedia(buffer, media, 1.0f, state_.offsetX, state_.offsetY, state_.scale);
|
||||
|
||||
return cycleComplete_;
|
||||
}
|
||||
private:
|
||||
AnimationState state_;
|
||||
long long delayMs_;
|
||||
std::chrono::steady_clock::time_point startTime_;
|
||||
bool cycleComplete_;
|
||||
};
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- NONE (애니메이션 없음) ---
|
||||
// ====================================================================
|
||||
class NoneAnimation : public AnimationStrategy {
|
||||
public:
|
||||
NoneAnimation(float speed) : AnimationStrategy(speed) { reset(); }
|
||||
void reset() override { state_ = AnimationState();
|
||||
callCount_ = 0;}
|
||||
AnimationState getState() const override { return state_; }
|
||||
|
||||
AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
AnimationState startState;
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
startState.offsetX = baseOffsetX;
|
||||
startState.offsetY = baseOffsetY;
|
||||
startState.scale = baseScale * 1.0f; // Zoom의 시작 배율은 1.0
|
||||
return startState;
|
||||
}
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) override {
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
renderer->calculateFitScaleAndOffset(media, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
state_.offsetX = baseOffsetX;
|
||||
state_.offsetY = baseOffsetY;
|
||||
state_.scale = baseScale;
|
||||
renderer->drawMedia(buffer, media, 1.0f, state_.offsetX, state_.offsetY, state_.scale);
|
||||
return callCount_++ > 120;
|
||||
}
|
||||
private:
|
||||
int callCount_;
|
||||
AnimationState state_;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include <android/native_window.h>
|
||||
#include "MediaAsset.h"
|
||||
|
||||
// 전방 선언: 순환 참조를 방지하기 위해 클래스의 이름만 먼저 알려줍니다.
|
||||
class Renderer;
|
||||
|
||||
/**
|
||||
* @brief 애니메이션의 현재 상태(결과값)를 담는 구조체입니다.
|
||||
* Renderer는 이 값을 받아 최종 그리기에 사용합니다.
|
||||
*/
|
||||
struct AnimationState {
|
||||
float offsetX = 0.0f;
|
||||
float offsetY = 0.0f;
|
||||
float scale = 1.0f;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 모든 애니메이션 전문가(Strategy) 클래스의 기반이 되는 인터페이스(추상 클래스)입니다.
|
||||
*/
|
||||
class AnimationStrategy {
|
||||
public:
|
||||
virtual ~AnimationStrategy() = default;
|
||||
|
||||
/**
|
||||
* @brief 매 프레임마다 호출되어 애니메이션을 직접 그리고, 상태를 반환합니다.
|
||||
* @return 애니메이션 한 사이클이 완료되었으면 true를 반환합니다.
|
||||
*/
|
||||
virtual bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer, MediaAsset& media, int surfaceWidth, int surfaceHeight) = 0;
|
||||
|
||||
/**
|
||||
* @brief 애니메이션 내부 상태를 초기화합니다.
|
||||
*/
|
||||
virtual void reset() = 0;
|
||||
|
||||
/**
|
||||
* @brief 현재 애니메이션 상태를 반환합니다.
|
||||
*/
|
||||
virtual AnimationState getState() const = 0;
|
||||
|
||||
// --- ⬇️ 자신의 시작 상태를 알려주는 함수 추가 ⬇️ ---
|
||||
virtual AnimationState getStartState(Renderer* renderer, MediaAsset& media, int surfaceWidth, int surfaceHeight) = 0;
|
||||
|
||||
protected:
|
||||
// 생성자에서 애니메이션 속도를 받아 저장합니다.
|
||||
AnimationStrategy(float speed) : animationSpeed_(speed) {}
|
||||
float animationSpeed_;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
# CMake 최소 버전 및 프로젝트 이름 설정
|
||||
cmake_minimum_required(VERSION 3.18.1)
|
||||
project("native_renderer")
|
||||
|
||||
# --- 1. 경로 변수 설정 ---
|
||||
# NOTE: 표준 안드로이드 프로젝트 구조에 맞춰 'main' 폴더를 경로에 포함합니다.
|
||||
set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/../../main/jniLibs/${ANDROID_ABI})
|
||||
|
||||
|
||||
# --- 2. 헤더 파일 경로 추가 ---
|
||||
include_directories(${JNI_LIBS_DIR}/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
# --- 3. 미리 빌드된 FFmpeg .so 라이브러리들을 IMPORTED 타겟으로 선언 ---
|
||||
# NOTE: 스크린샷의 파일 구조에 맞게 IMPORTED_LOCATION 경로에서 '/lib'를 제거했습니다.
|
||||
add_library(avformat SHARED IMPORTED)
|
||||
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavformat.so)
|
||||
|
||||
add_library(avcodec SHARED IMPORTED)
|
||||
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavcodec.so)
|
||||
|
||||
add_library(avutil SHARED IMPORTED)
|
||||
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavutil.so)
|
||||
|
||||
add_library(swscale SHARED IMPORTED)
|
||||
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libswscale.so)
|
||||
|
||||
add_library(swresample SHARED IMPORTED)
|
||||
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libswresample.so)
|
||||
|
||||
# 참고: 스크린샷에 보이는 다른 라이브러리들도 필요하다면 여기에 추가할 수 있습니다.
|
||||
#add_library(avdevice SHARED IMPORTED)
|
||||
#set_target_properties(avdevice PROPERTIES IMPORTED_LOCATION ${JNI_LIBS_DIR}/libavdevice.so)
|
||||
|
||||
|
||||
# --- 4. 네이티브 렌더러 라이브러리 빌드 설정 ---
|
||||
add_library(native_renderer SHARED
|
||||
native_renderer.cpp
|
||||
Renderer.cpp
|
||||
Preloader.cpp
|
||||
MediaAsset.cpp
|
||||
native_player.cpp
|
||||
PlayerEngine.cpp
|
||||
sonic.c
|
||||
)
|
||||
|
||||
|
||||
# --- 5. 최종 라이브러리 링크 ---
|
||||
find_library(log-lib log)
|
||||
find_library(android-lib android)
|
||||
find_library(nativewindow-lib nativewindow)
|
||||
|
||||
target_link_libraries(native_renderer
|
||||
# FFmpeg 라이브러리 타겟들
|
||||
avformat
|
||||
avcodec
|
||||
avutil
|
||||
swscale
|
||||
swresample
|
||||
jnigraphics
|
||||
swresample # 💡 추가!
|
||||
aaudio # 💡 추가! 안드로이드 네이티브 오디오
|
||||
# 안드로이드 기본 라이브러리들
|
||||
${log-lib}
|
||||
${android-lib}
|
||||
${nativewindow-lib}
|
||||
)
|
||||
@@ -0,0 +1,324 @@
|
||||
#include "MediaAsset.h"
|
||||
#include <android/log.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unistd.h> // for close()
|
||||
|
||||
// stb_image.h의 구현부를 여기에 단 한 번만 포함시킵니다.
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define LOG_TAG "MediaAsset"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
// --- ⬇️ FFmpeg Custom I/O를 위한 헬퍼 함수들 ⬇️ ---
|
||||
|
||||
// FFmpeg이 데이터를 요청할 때 호출될 읽기 함수
|
||||
static int read_packet(void *opaque, uint8_t *buf, int buf_size) {
|
||||
FILE* file = (FILE*)opaque;
|
||||
if (feof(file)) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
size_t bytes_read = fread(buf, 1, buf_size, file);
|
||||
if (bytes_read < buf_size) {
|
||||
if (ferror(file)) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
// FFmpeg이 위치 이동을 요청할 때 호출될 탐색 함수
|
||||
static int64_t seek_packet(void *opaque, int64_t offset, int whence) {
|
||||
FILE* file = (FILE*)opaque;
|
||||
// SEEK_SET, SEEK_CUR, SEEK_END, AVSEEK_SIZE
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
long current_pos = ftell(file);
|
||||
fseek(file, 0, SEEK_END);
|
||||
long size = ftell(file);
|
||||
fseek(file, current_pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
if (fseek(file, offset, whence) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return ftell(file);
|
||||
}
|
||||
|
||||
// --- 헬퍼 함수 끝 ---
|
||||
|
||||
|
||||
MediaAsset::MediaAsset(MediaAsset&& other) noexcept
|
||||
: type_(other.type_), width_(other.width_), height_(other.height_),
|
||||
imageData_(other.imageData_), rgbBuffer_(std::move(other.rgbBuffer_)),
|
||||
fmtCtx_(other.fmtCtx_), codecCtx_(other.codecCtx_), frame_(other.frame_),
|
||||
packet_(other.packet_), swsCtx_(other.swsCtx_), videoStreamIdx_(other.videoStreamIdx_) {
|
||||
other.type_ = Type::UNKNOWN;
|
||||
other.imageData_ = nullptr;
|
||||
other.fmtCtx_ = nullptr;
|
||||
other.codecCtx_ = nullptr;
|
||||
other.frame_ = nullptr;
|
||||
other.packet_ = nullptr;
|
||||
other.swsCtx_ = nullptr;
|
||||
}
|
||||
|
||||
MediaAsset& MediaAsset::operator=(MediaAsset&& other) noexcept {
|
||||
if (this != &other) {
|
||||
release();
|
||||
type_ = other.type_;
|
||||
width_ = other.width_;
|
||||
height_ = other.height_;
|
||||
imageData_ = other.imageData_;
|
||||
rgbBuffer_ = std::move(other.rgbBuffer_);
|
||||
fmtCtx_ = other.fmtCtx_;
|
||||
codecCtx_ = other.codecCtx_;
|
||||
frame_ = other.frame_;
|
||||
packet_ = other.packet_;
|
||||
swsCtx_ = other.swsCtx_;
|
||||
videoStreamIdx_ = other.videoStreamIdx_;
|
||||
other.type_ = Type::UNKNOWN;
|
||||
other.imageData_ = nullptr;
|
||||
other.fmtCtx_ = nullptr;
|
||||
other.codecCtx_ = nullptr;
|
||||
other.frame_ = nullptr;
|
||||
other.packet_ = nullptr;
|
||||
other.swsCtx_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MediaAsset::~MediaAsset() {
|
||||
release();
|
||||
}
|
||||
|
||||
// --- ⬇️ load(int fd) 함수 수정 ⬇️ ---
|
||||
bool MediaAsset::load(int fd) {
|
||||
if (fd < 0) {
|
||||
LOGE("Load failed: Invalid file descriptor.");
|
||||
return false;
|
||||
}
|
||||
release();
|
||||
|
||||
// 먼저 비디오로 로딩 시도 (Custom I/O 방식)
|
||||
if (loadVideoWithFFmpeg(fd)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 비디오 실패 시, 이미지로 로딩 시도 (/proc 경로 방식)
|
||||
LOGI("Video load failed for fd:%d, trying as image.", fd);
|
||||
std::string image_path = "/proc/self/fd/" + std::to_string(fd);
|
||||
if (loadImageWithStb(image_path)) {
|
||||
// 이미지 로딩 성공 시에는 fd를 여기서 닫아줌
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGE("Failed to load media from fd: %d", fd);
|
||||
close(fd); // 모든 로딩 실패 시에도 fd를 닫아줌
|
||||
return false;
|
||||
}
|
||||
|
||||
// path 기반 load 함수는 그대로 유지
|
||||
bool MediaAsset::load(const std::string& path) {
|
||||
release();
|
||||
size_t dotPos = path.find_last_of('.');
|
||||
if (dotPos == std::string::npos) {
|
||||
LOGE("Load failed: Could not find file extension in path: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
std::string extension = path.substr(dotPos + 1);
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
const std::vector<std::string> videoExts = {"mp4", "mkv", "avi", "mov", "webm","gif"};
|
||||
const std::vector<std::string> imageExts = {"jpg", "jpeg", "png", "bmp", "webp"};
|
||||
if (std::find(imageExts.begin(), imageExts.end(), extension) != imageExts.end()) {
|
||||
return loadImageWithStb(path);
|
||||
} else if (std::find(videoExts.begin(), videoExts.end(), extension) != videoExts.end()) {
|
||||
// path 기반 비디오 로딩은 이제 fd 기반 로딩을 호출하지 않음
|
||||
return loadVideoWithFFmpeg(path.c_str());
|
||||
}
|
||||
LOGE("Load failed: Unsupported file format for path: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MediaAsset::loadImageWithStb(const std::string& path) {
|
||||
type_ = Type::IMAGE;
|
||||
imageData_ = stbi_load(path.c_str(), &width_, &height_, nullptr, 4);
|
||||
if (!imageData_) {
|
||||
LOGE("Failed to load image with stb_image: %s", stbi_failure_reason());
|
||||
return false;
|
||||
}
|
||||
LOGI("Successfully loaded image: %s (%dx%d)", path.c_str(), width_, height_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// --- ⬇️ loadVideoWithFFmpeg 함수를 오버로딩하여 Custom I/O 로직 추가 ⬇️ ---
|
||||
bool MediaAsset::loadVideoWithFFmpeg(int fd) {
|
||||
type_ = Type::VIDEO;
|
||||
|
||||
// 1. fd를 FILE* 스트림으로 변환
|
||||
FILE* file = fdopen(fd, "rb");
|
||||
if (!file) {
|
||||
LOGE("Custom I/O: Failed to fdopen for fd: %d", fd);
|
||||
close(fd); // fdopen 실패 시 fd를 직접 닫음
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. FFmpeg Custom I/O를 위한 버퍼 및 컨텍스트 생성
|
||||
const int buffer_size = 4096;
|
||||
unsigned char* buffer = (unsigned char*)av_malloc(buffer_size);
|
||||
AVIOContext* ioCtx = avio_alloc_context(
|
||||
buffer, buffer_size, 0, file, &read_packet, nullptr, &seek_packet
|
||||
);
|
||||
if (!ioCtx) {
|
||||
LOGE("Custom I/O: Failed to avio_alloc_context");
|
||||
fclose(file);
|
||||
av_free(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
fmtCtx_ = avformat_alloc_context();
|
||||
fmtCtx_->pb = ioCtx; // 생성한 I/O 컨텍스트를 포맷 컨텍스트에 연결
|
||||
|
||||
// 3. avformat_open_input 호출 (첫 번째 인자로 nullptr 전달)
|
||||
if (avformat_open_input(&fmtCtx_, nullptr, nullptr, nullptr) != 0) {
|
||||
LOGE("Custom I/O: avformat_open_input failed");
|
||||
// 실패 시 자원 정리 (fmtCtx_는 여기서 해제하면 안됨)
|
||||
avio_context_free(&fmtCtx_->pb); // fmtCtx_가 소유권을 가져갔으므로 이렇게 해제
|
||||
fmtCtx_ = nullptr;
|
||||
// fclose는 이미 ioCtx가 관리하므로 호출 불필요
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- 이후 로직은 기존과 동일 ---
|
||||
if (avformat_find_stream_info(fmtCtx_, nullptr) < 0) {
|
||||
LOGE("Could not find stream information");
|
||||
release(); return false;
|
||||
}
|
||||
const AVCodec* codec = nullptr;
|
||||
videoStreamIdx_ = av_find_best_stream(fmtCtx_, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
|
||||
if (videoStreamIdx_ < 0) {
|
||||
LOGE("Could not find a video stream");
|
||||
release(); return false;
|
||||
}
|
||||
AVStream* stream = fmtCtx_->streams[videoStreamIdx_];
|
||||
if (stream->avg_frame_rate.den != 0) {
|
||||
fps_ = av_q2d(stream->avg_frame_rate);
|
||||
} else {
|
||||
fps_ = 30.0; // FPS 정보가 없는 경우 기본값 30
|
||||
}
|
||||
LOGI("Video FPS detected: %f", fps_);
|
||||
codecCtx_ = avcodec_alloc_context3(codec);
|
||||
if (!codecCtx_ || avcodec_parameters_to_context(codecCtx_, fmtCtx_->streams[videoStreamIdx_]->codecpar) < 0) {
|
||||
LOGE("Failed to create codec context");
|
||||
release(); return false;
|
||||
}
|
||||
if (avcodec_open2(codecCtx_, codec, nullptr) < 0) {
|
||||
LOGE("Could not open codec");
|
||||
release(); return false;
|
||||
}
|
||||
frame_ = av_frame_alloc();
|
||||
packet_ = av_packet_alloc();
|
||||
if (!frame_ || !packet_) {
|
||||
LOGE("Could not allocate frame or packet");
|
||||
release(); return false;
|
||||
}
|
||||
width_ = codecCtx_->width;
|
||||
height_ = codecCtx_->height;
|
||||
swsCtx_ = sws_getContext(width_, height_, codecCtx_->pix_fmt, width_, height_, AV_PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
if (!swsCtx_) {
|
||||
LOGE("Could not create SwsContext");
|
||||
release(); return false;
|
||||
}
|
||||
rgbBuffer_.resize(width_ * height_ * 4);
|
||||
|
||||
LOGI("Successfully loaded video via Custom I/O from fd: %d", fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 기존의 path 기반 비디오 로딩 함수 (이제 거의 사용되지 않음)
|
||||
bool MediaAsset::loadVideoWithFFmpeg(const std::string& path) {
|
||||
type_ = Type::VIDEO;
|
||||
if (avformat_open_input(&fmtCtx_, path.c_str(), nullptr, nullptr) != 0) {
|
||||
LOGE("Could not open video file: %s", path.c_str());
|
||||
release(); return false;
|
||||
}
|
||||
// ... (이하 로직은 Custom I/O 버전과 동일)
|
||||
if (avformat_find_stream_info(fmtCtx_, nullptr) < 0) { release(); return false; }
|
||||
const AVCodec* codec = nullptr;
|
||||
videoStreamIdx_ = av_find_best_stream(fmtCtx_, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
|
||||
if (videoStreamIdx_ < 0) { release(); return false; }
|
||||
// --- ⬇️ FPS 추출 코드 추가 (동일한 코드) ⬇️ ---
|
||||
AVStream* stream = fmtCtx_->streams[videoStreamIdx_];
|
||||
if (stream->avg_frame_rate.den != 0) {
|
||||
fps_ = av_q2d(stream->avg_frame_rate);
|
||||
} else {
|
||||
fps_ = 30.0;
|
||||
}
|
||||
LOGI("Video FPS detected: %f", fps_);
|
||||
codecCtx_ = avcodec_alloc_context3(codec);
|
||||
if (!codecCtx_ || avcodec_parameters_to_context(codecCtx_, fmtCtx_->streams[videoStreamIdx_]->codecpar) < 0) { release(); return false; }
|
||||
if (avcodec_open2(codecCtx_, codec, nullptr) < 0) { release(); return false; }
|
||||
frame_ = av_frame_alloc(); packet_ = av_packet_alloc();
|
||||
if (!frame_ || !packet_) { release(); return false; }
|
||||
width_ = codecCtx_->width; height_ = codecCtx_->height;
|
||||
swsCtx_ = sws_getContext(width_, height_, codecCtx_->pix_fmt, width_, height_, AV_PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
if (!swsCtx_) { release(); return false; }
|
||||
rgbBuffer_.resize(width_ * height_ * 4);
|
||||
LOGI("Successfully loaded video from path: %s", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void MediaAsset::release() {
|
||||
if (type_ == Type::IMAGE && imageData_) {
|
||||
stbi_image_free(imageData_);
|
||||
}
|
||||
imageData_ = nullptr;
|
||||
if (packet_) av_packet_free(&packet_);
|
||||
if (frame_) av_frame_free(&frame_);
|
||||
// if (codecCtx_) avcodec_close(codecCtx_);
|
||||
// if (codecCtx_) avcodec_free_context(&codecCtx_);
|
||||
if (codecCtx_) avcodec_free_context(&codecCtx_);
|
||||
|
||||
if (fmtCtx_) {
|
||||
// Custom I/O로 열었을 경우, IO 컨텍스트의 버퍼를 직접 해제해주어야 함
|
||||
if (fmtCtx_->pb) {
|
||||
if (fmtCtx_->pb->buffer) {
|
||||
av_free(fmtCtx_->pb->buffer);
|
||||
fmtCtx_->pb->buffer = nullptr;
|
||||
}
|
||||
// FILE*는 avio_context_free가 닫아주지 않으므로, 우리가 직접 닫아야 함
|
||||
if (fmtCtx_->pb->opaque) {
|
||||
fclose((FILE*)fmtCtx_->pb->opaque);
|
||||
fmtCtx_->pb->opaque = nullptr;
|
||||
}
|
||||
avio_context_free(&fmtCtx_->pb);
|
||||
}
|
||||
avformat_close_input(&fmtCtx_);
|
||||
}
|
||||
if (swsCtx_) sws_freeContext(swsCtx_);
|
||||
|
||||
packet_ = nullptr;
|
||||
frame_ = nullptr;
|
||||
codecCtx_ = nullptr;
|
||||
fmtCtx_ = nullptr;
|
||||
swsCtx_ = nullptr;
|
||||
type_ = Type::UNKNOWN;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
videoStreamIdx_ = -1;
|
||||
rgbBuffer_.clear();
|
||||
}
|
||||
|
||||
bool MediaAsset::isValid() const {
|
||||
if (type_ == Type::IMAGE) {
|
||||
return imageData_ != nullptr && width_ > 0 && height_ > 0;
|
||||
} else if (type_ == Type::VIDEO) {
|
||||
return fmtCtx_ != nullptr && codecCtx_ != nullptr && frame_ != nullptr && swsCtx_ != nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
||||
// C언어 라이브러리와의 호환성을 위한 extern "C" 블록
|
||||
extern "C" {
|
||||
// NOTE: 가장 기초가 되는 avutil.h를 제일 먼저 포함해야 합니다.
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
class MediaAsset {
|
||||
public:
|
||||
enum class Type { UNKNOWN, IMAGE, VIDEO };
|
||||
|
||||
MediaAsset() = default;
|
||||
~MediaAsset();
|
||||
|
||||
// 복사를 방지하고 자원의 소유권을 효율적으로 이전하기 위한 이동 생성자 및 연산자
|
||||
MediaAsset(MediaAsset&& other) noexcept;
|
||||
MediaAsset& operator=(MediaAsset&& other) noexcept;
|
||||
|
||||
// 파일을 로드하는 메인 함수 (오버로딩)
|
||||
bool load(const std::string& path);
|
||||
bool load(int fd);
|
||||
|
||||
// 모든 자원을 해제하는 함수
|
||||
void release();
|
||||
|
||||
// 현재 미디어가 유효한지 확인
|
||||
bool isValid() const;
|
||||
|
||||
// Getter 함수들
|
||||
Type getType() const { return type_; }
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
const uint8_t* getImageData() const { return imageData_; }
|
||||
std::vector<uint8_t>& getRgbBuffer() { return rgbBuffer_; }
|
||||
const std::vector<uint8_t>& getRgbBuffer() const { return rgbBuffer_; }
|
||||
|
||||
|
||||
// FFmpeg 비디오 처리를 위한 Getter 함수들
|
||||
AVFormatContext* getFormatContext() const { return fmtCtx_; }
|
||||
AVCodecContext* getCodecContext() const { return codecCtx_; }
|
||||
AVFrame* getFrame() const { return frame_; }
|
||||
AVPacket* getPacket() const { return packet_; }
|
||||
SwsContext* getSwsContext() const { return swsCtx_; }
|
||||
int getVideoStreamIndex() const { return videoStreamIdx_; }
|
||||
double getFps() const { return fps_; } // <-- FPS getter 추가
|
||||
|
||||
private:
|
||||
bool loadInternal(const std::string& path);
|
||||
// --- ⬇️ 수정된 부분: int fd를 받는 함수 선언 추가 ⬇️ ---
|
||||
bool loadVideoWithFFmpeg(const std::string& path);
|
||||
bool loadVideoWithFFmpeg(int fd); // Custom I/O를 위한 오버로딩
|
||||
bool loadImageWithStb(const std::string& path);
|
||||
// --- 수정 끝 ---
|
||||
|
||||
Type type_ = Type::UNKNOWN;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
uint8_t* imageData_ = nullptr;
|
||||
std::vector<uint8_t> rgbBuffer_;
|
||||
AVFormatContext* fmtCtx_ = nullptr;
|
||||
AVCodecContext* codecCtx_ = nullptr;
|
||||
AVFrame* frame_ = nullptr;
|
||||
AVPacket* packet_ = nullptr;
|
||||
SwsContext* swsCtx_ = nullptr;
|
||||
int videoStreamIdx_ = -1;
|
||||
double fps_ = 0.0; // <-- FPS 저장 변수 추가
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by JIBUM HAN on 2026. 4. 11..
|
||||
//
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
class PacketQueue {
|
||||
private:
|
||||
std::queue<AVPacket*> queue_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_;
|
||||
int sizeBytes_ = 0;
|
||||
bool abortRequest_ = false; // 플레이어 종료 시 대기 중인 스레드를 깨우기 위함
|
||||
|
||||
public:
|
||||
void abort() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
abortRequest_ = true;
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
void start() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
abortRequest_ = false;
|
||||
}
|
||||
|
||||
bool push(AVPacket* pkt) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (abortRequest_) return false;
|
||||
|
||||
// 패킷 복사 (메모리 소유권을 큐로 넘김)
|
||||
AVPacket* pkt1 = av_packet_alloc();
|
||||
av_packet_move_ref(pkt1, pkt);
|
||||
|
||||
queue_.push(pkt1);
|
||||
sizeBytes_ += pkt1->size;
|
||||
cond_.notify_one(); // 데이터를 기다리며 자고 있는 디코딩 스레드를 깨움
|
||||
return true;
|
||||
}
|
||||
|
||||
// 데이터를 꺼낼 때 큐가 비어있으면 block(대기) 상태가 됨
|
||||
AVPacket* pop() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_.wait(lock, [this]() { return !queue_.empty() || abortRequest_; });
|
||||
|
||||
if (abortRequest_ || queue_.empty()) return nullptr;
|
||||
|
||||
AVPacket* pkt = queue_.front();
|
||||
queue_.pop();
|
||||
sizeBytes_ -= pkt->size;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
void flush() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
while (!queue_.empty()) {
|
||||
AVPacket* pkt = queue_.front();
|
||||
queue_.pop();
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
sizeBytes_ = 0;
|
||||
}
|
||||
|
||||
int getSizeBytes() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return sizeBytes_;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,627 @@
|
||||
#include "PlayerEngine.h"
|
||||
#include <android/log.h>
|
||||
#include <chrono>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define LOG_TAG "NativePlayerEngine"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
const int MIN_BUFFER_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
static int custom_read_packet(void *opaque, uint8_t *buf, int buf_size) {
|
||||
int fd = (int)(intptr_t)opaque;
|
||||
int ret = read(fd, buf, buf_size);
|
||||
if (ret == 0) return AVERROR_EOF;
|
||||
if (ret < 0) return AVERROR(errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t custom_seek_packet(void *opaque, int64_t offset, int whence) {
|
||||
int fd = (int)(intptr_t)opaque;
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == 0) return st.st_size;
|
||||
return AVERROR(errno);
|
||||
}
|
||||
whence &= ~AVSEEK_FORCE;
|
||||
int64_t ret = lseek(fd, offset, whence);
|
||||
return ret < 0 ? AVERROR(errno) : ret;
|
||||
}
|
||||
|
||||
PlayerEngine::PlayerEngine(JavaVM* vm, jobject listenerObj) : jvm_(vm) {
|
||||
JNIEnv* env;
|
||||
jvm_->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
listenerObj_ = env->NewGlobalRef(listenerObj);
|
||||
jclass clazz = env->GetObjectClass(listenerObj_);
|
||||
|
||||
auto safeGetMethod = [&](const char* name, const char* sig) -> jmethodID {
|
||||
jmethodID id = env->GetMethodID(clazz, name, sig);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionClear();
|
||||
LOGE("❌ Failed to find method: %s %s", name, sig);
|
||||
return nullptr;
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
subtitleMethodId_ = safeGetMethod("onSubtitleTextDecoded", "(Ljava/lang/String;)V");
|
||||
videoSizeMethodId_ = safeGetMethod("onVideoSizeChanged", "(II)V");
|
||||
preparedMethodId_ = safeGetMethod("onNativePrepared", "()V");
|
||||
errorMethodId_ = safeGetMethod("onNativeError", "(ILjava/lang/String;)V");
|
||||
}
|
||||
|
||||
PlayerEngine::~PlayerEngine() {
|
||||
stop();
|
||||
if (prepareThread_.joinable()) prepareThread_.join(); // 준비 스레드 대기
|
||||
if (listenerObj_) {
|
||||
JNIEnv* env; jvm_->GetEnv((void**)&env, JNI_VERSION_1_6);
|
||||
env->DeleteGlobalRef(listenerObj_);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerEngine::setDataSource(int videoFd, int subtitleFd) {
|
||||
videoFd_ = videoFd;
|
||||
subtitleFd_ = subtitleFd;
|
||||
}
|
||||
|
||||
void PlayerEngine::prepareAsync() {
|
||||
if (isPrepared_ || prepareThread_.joinable()) return;
|
||||
prepareThread_ = std::thread(&PlayerEngine::prepareInternal, this);
|
||||
}
|
||||
|
||||
void PlayerEngine::prepareInternal() {
|
||||
JNIEnv* env;
|
||||
jvm_->AttachCurrentThread(&env, nullptr);
|
||||
|
||||
auto sendError = [&](int code, const char* msg) {
|
||||
LOGE("Prepare Error [%d]: %s", code, msg);
|
||||
if (errorMethodId_) {
|
||||
jstring jMsg = env->NewStringUTF(msg);
|
||||
env->CallVoidMethod(listenerObj_, errorMethodId_, code, jMsg);
|
||||
env->DeleteLocalRef(jMsg);
|
||||
}
|
||||
jvm_->DetachCurrentThread();
|
||||
};
|
||||
|
||||
int avio_buffer_size = 32768;
|
||||
uint8_t* avio_buffer = (uint8_t*)av_malloc(avio_buffer_size);
|
||||
AVIOContext* avio_ctx = avio_alloc_context(avio_buffer, avio_buffer_size, 0, (void*)(intptr_t)videoFd_, custom_read_packet, nullptr, custom_seek_packet);
|
||||
fmt_ctx_ = avformat_alloc_context();
|
||||
fmt_ctx_->pb = avio_ctx;
|
||||
|
||||
if (avformat_open_input(&fmt_ctx_, nullptr, nullptr, nullptr) < 0) {
|
||||
return sendError(-1001, "Failed to open video file. Invalid FD or Format.");
|
||||
}
|
||||
if (avformat_find_stream_info(fmt_ctx_, nullptr) < 0) {
|
||||
return sendError(-1002, "Failed to retrieve stream information.");
|
||||
}
|
||||
|
||||
subtitle_tracks_info_ = "";
|
||||
for (unsigned int i = 0; i < fmt_ctx_->nb_streams; i++) {
|
||||
auto type = fmt_ctx_->streams[i]->codecpar->codec_type;
|
||||
if (type == AVMEDIA_TYPE_VIDEO && video_stream_idx_ < 0) video_stream_idx_ = i;
|
||||
else if (type == AVMEDIA_TYPE_AUDIO && audio_stream_idx_ < 0) audio_stream_idx_ = i;
|
||||
else if (type == AVMEDIA_TYPE_SUBTITLE) {
|
||||
AVDictionaryEntry *lang = av_dict_get(fmt_ctx_->streams[i]->metadata, "language", nullptr, 0);
|
||||
AVDictionaryEntry *title = av_dict_get(fmt_ctx_->streams[i]->metadata, "title", nullptr, 0);
|
||||
std::string trackName = "Track " + std::to_string(i);
|
||||
if (title) trackName = title->value;
|
||||
else if (lang) trackName = lang->value;
|
||||
subtitle_tracks_info_ += std::to_string(i) + ":" + trackName + ",";
|
||||
}
|
||||
}
|
||||
|
||||
if (video_stream_idx_ >= 0) {
|
||||
auto par = fmt_ctx_->streams[video_stream_idx_]->codecpar;
|
||||
auto codec = avcodec_find_decoder(par->codec_id);
|
||||
video_codec_ctx_ = avcodec_alloc_context3(codec);
|
||||
avcodec_parameters_to_context(video_codec_ctx_, par);
|
||||
if (avcodec_open2(video_codec_ctx_, codec, nullptr) == 0 && videoSizeMethodId_) {
|
||||
env->CallVoidMethod(listenerObj_, videoSizeMethodId_, video_codec_ctx_->width, video_codec_ctx_->height);
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_stream_idx_ >= 0) {
|
||||
auto par = fmt_ctx_->streams[audio_stream_idx_]->codecpar;
|
||||
auto codec = avcodec_find_decoder(par->codec_id);
|
||||
audio_codec_ctx_ = avcodec_alloc_context3(codec);
|
||||
avcodec_parameters_to_context(audio_codec_ctx_, par);
|
||||
if (avcodec_open2(audio_codec_ctx_, codec, nullptr) == 0) {
|
||||
AVChannelLayout out_ch; av_channel_layout_default(&out_ch, 2);
|
||||
swr_alloc_set_opts2(&swr_ctx_, &out_ch, AV_SAMPLE_FMT_S16, 48000, &audio_codec_ctx_->ch_layout, audio_codec_ctx_->sample_fmt, audio_codec_ctx_->sample_rate, 0, nullptr);
|
||||
swr_init(swr_ctx_);
|
||||
|
||||
AAudioStreamBuilder* builder;
|
||||
AAudio_createStreamBuilder(&builder);
|
||||
AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_I16);
|
||||
AAudioStreamBuilder_setChannelCount(builder, 2);
|
||||
AAudioStreamBuilder_setSampleRate(builder, 48000);
|
||||
AAudioStreamBuilder_openStream(builder, &audio_stream_);
|
||||
|
||||
// 💡 1. 버퍼 크기를 가용 가능한 최대치로 늘려서 비디오 렌더링 딜레이에 대비합니다.
|
||||
AAudioStream_setBufferSizeInFrames(audio_stream_, AAudioStream_getBufferCapacityInFrames(audio_stream_));
|
||||
|
||||
// 🚀 Sonic 초기화 추가 (Sample Rate 48000, Channels 2)
|
||||
sonic_stream_ = sonicCreateStream(48000, 2);
|
||||
sonicSetSpeed(sonic_stream_, 1.0f); // 초기 배속 1.0
|
||||
|
||||
// 💡 2. 여기서 호출하던 AAudioStream_requestStart(audio_stream_); 를 삭제합니다! (대기 상태로 둠)
|
||||
|
||||
AAudioStreamBuilder_delete(builder);
|
||||
}
|
||||
}
|
||||
|
||||
isPrepared_ = true;
|
||||
if (preparedMethodId_) env->CallVoidMethod(listenerObj_, preparedMethodId_);
|
||||
jvm_->DetachCurrentThread();
|
||||
}
|
||||
|
||||
void PlayerEngine::play(ANativeWindow* window) {
|
||||
if (!isPrepared_) return;
|
||||
if (isPlaying_) return;
|
||||
|
||||
window_ = window;
|
||||
ANativeWindow_acquire(window_);
|
||||
isPlaying_ = true;
|
||||
abortRequest_ = false;
|
||||
|
||||
videoQueue_.start();
|
||||
audioQueue_.start();
|
||||
|
||||
if (audio_stream_) AAudioStream_requestStart(audio_stream_);
|
||||
|
||||
// 🚀 3개의 스레드 동시 가동
|
||||
readThread_ = std::thread(&PlayerEngine::readThreadLoop, this);
|
||||
videoThread_ = std::thread(&PlayerEngine::videoThreadLoop, this);
|
||||
audioThread_ = std::thread(&PlayerEngine::audioThreadLoop, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PlayerEngine::pause() {
|
||||
isPaused_ = true;
|
||||
// 💡 영상이 일시정지되면 오디오 버퍼도 소모되지 않게 멈춰줍니다.
|
||||
if (audio_stream_) AAudioStream_requestPause(audio_stream_);
|
||||
}
|
||||
|
||||
void PlayerEngine::stop() {
|
||||
if (!isPlaying_) return;
|
||||
isPlaying_ = false;
|
||||
abortRequest_ = true;
|
||||
|
||||
// 큐를 깨워서 멈춰있는 스레드들을 탈출시킴
|
||||
videoQueue_.abort();
|
||||
audioQueue_.abort();
|
||||
|
||||
if (readThread_.joinable()) readThread_.join();
|
||||
if (videoThread_.joinable()) videoThread_.join();
|
||||
if (audioThread_.joinable()) audioThread_.join();
|
||||
|
||||
videoQueue_.flush();
|
||||
audioQueue_.flush();
|
||||
if (sonic_stream_) {
|
||||
sonicDestroyStream(sonic_stream_);
|
||||
sonic_stream_ = nullptr;
|
||||
}
|
||||
if (window_) { ANativeWindow_release(window_); window_ = nullptr; }
|
||||
}
|
||||
|
||||
void PlayerEngine::seekBy(double seconds) {
|
||||
seekTargetOffset_ = seconds;
|
||||
seekReq_ = true;
|
||||
}
|
||||
|
||||
void PlayerEngine::setSpeed(float speed) {
|
||||
float oldSpeed = playbackSpeed_.load();
|
||||
playbackSpeed_ = speed > 0.0f ? speed : 1.0f;
|
||||
|
||||
|
||||
// 💡 배속이 종료(1.0으로 복귀)될 때만 특별 처리를 위해 플래그 설정
|
||||
if (oldSpeed != 1.0f && speed == 1.0f) {
|
||||
seekReq_ = true; // 강제 Flush를 위해 Seek 로직을 재활용합니다.
|
||||
isAbsoluteSeek_ = true;
|
||||
seekTargetSec_ = currentPosSec_; // 현재 비디오 위치로 오디오를 강제 고정
|
||||
}
|
||||
if (sonic_stream_) {
|
||||
sonicSetSpeed(sonic_stream_, playbackSpeed_.load());
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerEngine::sendSubtitleToKotlin(const char* text) {
|
||||
if (!jvm_ || !listenerObj_ || !subtitleMethodId_ || !text) return;
|
||||
JNIEnv* env; bool attached = false;
|
||||
if (jvm_->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { jvm_->AttachCurrentThread(&env, nullptr); attached = true; }
|
||||
jstring jText = env->NewStringUTF(text);
|
||||
env->CallVoidMethod(listenerObj_, subtitleMethodId_, jText);
|
||||
env->DeleteLocalRef(jText);
|
||||
if (attached) jvm_->DetachCurrentThread();
|
||||
}
|
||||
|
||||
double PlayerEngine::getDuration() const {
|
||||
if (fmt_ctx_ && fmt_ctx_->duration != AV_NOPTS_VALUE) {
|
||||
return (double)fmt_ctx_->duration / AV_TIME_BASE;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void PlayerEngine::seekTo(double seconds) {
|
||||
seekTargetSec_ = seconds;
|
||||
isAbsoluteSeek_ = true;
|
||||
seekReq_ = true;
|
||||
}
|
||||
|
||||
//void PlayerEngine::renderLoop() {
|
||||
// LOGI("🚀 Player render loop started (AV Sync & Performance Optimized)");
|
||||
//
|
||||
// AVFrame* frame = av_frame_alloc();
|
||||
// AVPacket* pkt = av_packet_alloc();
|
||||
// int last_win_w = 0, last_win_h = 0;
|
||||
//
|
||||
// // 1. 영상의 실제 FPS 정보를 기반으로 프레임당 지연 시간(마이크로초) 계산
|
||||
// double fps = av_q2d(fmt_ctx_->streams[video_stream_idx_]->avg_frame_rate);
|
||||
// if (fps <= 0) fps = 23.976; // 정보가 없을 경우 영화 표준 프레임 레이트 적용
|
||||
// int64_t frame_delay_us = (int64_t)(1000000.0 / fps);
|
||||
//
|
||||
// while (isPlaying_) {
|
||||
// // 일시정지 처리
|
||||
// if (isPaused_) {
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // Seek(탐색) 요청 처리
|
||||
// if (seekReq_) {
|
||||
// int64_t seek_target;
|
||||
// if (isAbsoluteSeek_) {
|
||||
// seek_target = (int64_t)(seekTargetSec_ * AV_TIME_BASE);
|
||||
// } else {
|
||||
// seek_target = (int64_t)((currentPosSec_ + seekTargetOffset_) * AV_TIME_BASE);
|
||||
// }
|
||||
//
|
||||
// av_seek_frame(fmt_ctx_, -1, seek_target, AVSEEK_FLAG_BACKWARD);
|
||||
//
|
||||
// if (video_codec_ctx_) avcodec_flush_buffers(video_codec_ctx_);
|
||||
// if (audio_codec_ctx_) avcodec_flush_buffers(audio_codec_ctx_);
|
||||
//
|
||||
// if (audio_stream_) {
|
||||
// AAudioStream_requestPause(audio_stream_);
|
||||
// AAudioStream_requestFlush(audio_stream_);
|
||||
// AAudioStream_requestStart(audio_stream_);
|
||||
// }
|
||||
// seekReq_ = false;
|
||||
// isAbsoluteSeek_ = false; // 플래그 초기화
|
||||
// }
|
||||
//
|
||||
// float currentSpeed = playbackSpeed_.load();
|
||||
//
|
||||
// // 패킷 읽기
|
||||
// if (av_read_frame(fmt_ctx_, pkt) < 0) break;
|
||||
//
|
||||
// // --- 비디오 스트림 처리 ---
|
||||
// if (pkt->stream_index == video_stream_idx_) {
|
||||
// // 💡 프레임 렌더링 시작 시간 기록
|
||||
// auto frame_start = std::chrono::high_resolution_clock::now();
|
||||
//
|
||||
// avcodec_send_packet(video_codec_ctx_, pkt);
|
||||
// while (avcodec_receive_frame(video_codec_ctx_, frame) == 0) {
|
||||
// // 현재 재생 시간(초) 업데이트
|
||||
// currentPosSec_ = frame->pts * av_q2d(fmt_ctx_->streams[video_stream_idx_]->time_base);
|
||||
//
|
||||
// if (window_) {
|
||||
// int w = ANativeWindow_getWidth(window_), h = ANativeWindow_getHeight(window_);
|
||||
// if (!sws_ctx_ || w != last_win_w || h != last_win_h) {
|
||||
// if (sws_ctx_) sws_freeContext(sws_ctx_);
|
||||
// sws_ctx_ = sws_getContext(frame->width, frame->height, video_codec_ctx_->pix_fmt, w, h, AV_PIX_FMT_RGBA, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
// last_win_w = w; last_win_h = h;
|
||||
// }
|
||||
//
|
||||
// ANativeWindow_Buffer buffer;
|
||||
// if (ANativeWindow_lock(window_, &buffer, nullptr) == 0) {
|
||||
// uint8_t* dst_data[4] = { (uint8_t*)buffer.bits, nullptr, nullptr, nullptr };
|
||||
// int dst_line[4] = { buffer.stride * 4, 0, 0, 0 };
|
||||
// if (sws_ctx_) sws_scale(sws_ctx_, frame->data, frame->linesize, 0, frame->height, dst_data, dst_line);
|
||||
// ANativeWindow_unlockAndPost(window_);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 💡 [핵심 동기화] 연산에 소요된 시간을 제외한 나머지 시간만 대기
|
||||
// auto frame_end = std::chrono::high_resolution_clock::now();
|
||||
// int64_t actual_render_time = std::chrono::duration_cast<std::chrono::microseconds>(frame_end - frame_start).count();
|
||||
//
|
||||
// // 배속(currentSpeed)을 고려한 대기 시간 계산
|
||||
// int64_t wait_time = (int64_t)((frame_delay_us / currentSpeed) - actual_render_time);
|
||||
//
|
||||
// if (wait_time > 0) {
|
||||
// std::this_thread::sleep_for(std::chrono::microseconds(wait_time));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // --- 오디오 스트림 처리 ---
|
||||
// else if (pkt->stream_index == audio_stream_idx_) {
|
||||
// // 정속 재생(1.0)일 때만 오디오 재생 (오디오 배속은 로직이 복잡하므로 정속 위주 최적화)
|
||||
// if (currentSpeed == 1.0f) {
|
||||
// avcodec_send_packet(audio_codec_ctx_, pkt);
|
||||
// while (avcodec_receive_frame(audio_codec_ctx_, frame) == 0) {
|
||||
// if (swr_ctx_ && audio_stream_) {
|
||||
// int out_samples = swr_get_out_samples(swr_ctx_, frame->nb_samples);
|
||||
// uint8_t* out_buf = (uint8_t*)malloc(out_samples * 4);
|
||||
// int converted_samples = swr_convert(swr_ctx_, &out_buf, out_samples, (const uint8_t**)frame->data, frame->nb_samples);
|
||||
//
|
||||
// if (converted_samples > 0) {
|
||||
// // 💡 [수정] 타임아웃을 0으로 설정하여 오디오 버퍼가 꽉 차도 비디오 스레드가 멈추지 않게 함
|
||||
// AAudioStream_write(audio_stream_, out_buf, converted_samples, 0);
|
||||
// }
|
||||
// free(out_buf);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // --- 자막 스트림 처리 ---
|
||||
// else if (pkt->stream_index == current_sub_stream_idx_) {
|
||||
// AVSubtitle sub; int got_sub = 0;
|
||||
// avcodec_decode_subtitle2(sub_codec_ctx_, &sub, &got_sub, pkt);
|
||||
// if (got_sub) {
|
||||
// for (unsigned int i = 0; i < sub.num_rects; i++) {
|
||||
// if (sub.rects[i]->type == SUBTITLE_TEXT && sub.rects[i]->text) sendSubtitleToKotlin(sub.rects[i]->text);
|
||||
// else if (sub.rects[i]->type == SUBTITLE_ASS && sub.rects[i]->ass) sendSubtitleToKotlin(sub.rects[i]->ass);
|
||||
// }
|
||||
// avsubtitle_free(&sub);
|
||||
// }
|
||||
// }
|
||||
// av_packet_unref(pkt);
|
||||
// }
|
||||
//
|
||||
// // 자원 해제 로직
|
||||
// if (audio_stream_) {
|
||||
// AAudioStream_requestStop(audio_stream_);
|
||||
// AAudioStream_close(audio_stream_);
|
||||
// audio_stream_ = nullptr;
|
||||
// }
|
||||
// av_frame_free(&frame);
|
||||
// av_packet_free(&pkt);
|
||||
// if (swr_ctx_) swr_free(&swr_ctx_);
|
||||
// if (sws_ctx_) sws_freeContext(sws_ctx_);
|
||||
// if (video_codec_ctx_) avcodec_free_context(&video_codec_ctx_);
|
||||
// if (audio_codec_ctx_) avcodec_free_context(&audio_codec_ctx_);
|
||||
// if (fmt_ctx_) avformat_close_input(&fmt_ctx_);
|
||||
//
|
||||
// LOGI("🏁 Player loop finished gracefully.");
|
||||
//}
|
||||
|
||||
|
||||
void PlayerEngine::readThreadLoop() {
|
||||
AVPacket* pkt = av_packet_alloc();
|
||||
const int MAX_QUEUE_SIZE = 15 * 1024 * 1024;
|
||||
|
||||
while (!abortRequest_) {
|
||||
|
||||
// 🚀 [탐색(Seek) 처리 로직]
|
||||
if (seekReq_) {
|
||||
// 1. 목표 시간 계산
|
||||
double targetSec = isAbsoluteSeek_ ? seekTargetSec_.load() : (currentPosSec_ + seekTargetOffset_.load());
|
||||
int64_t seek_target = (int64_t)(targetSec * AV_TIME_BASE);
|
||||
|
||||
// 2. FFmpeg 탐색 수행
|
||||
av_seek_frame(fmt_ctx_, -1, seek_target, AVSEEK_FLAG_BACKWARD);
|
||||
|
||||
// 3. 💡 [핵심] 기존에 큐에 쌓여있던 옛날 패킷들을 전부 폭파!
|
||||
videoQueue_.flush();
|
||||
audioQueue_.flush();
|
||||
|
||||
// 4. 코덱 내부에 남아있는 옛날 프레임 찌꺼기 초기화
|
||||
// if (video_codec_ctx_) avcodec_flush_buffers(video_codec_ctx_);
|
||||
// videoCodecFlushReq_ = false;
|
||||
// if (audio_codec_ctx_) avcodec_flush_buffers(audio_codec_ctx_);
|
||||
// // 이미 비웠으므로 false
|
||||
// audioCodecFlushReq_ = false;
|
||||
// if (sonic_stream_) {
|
||||
// sonicFlushStream(sonic_stream_);
|
||||
// }
|
||||
//
|
||||
// // 5. 오디오 장치 초기화 (틱 잡음 방지)
|
||||
// if (audio_stream_) {
|
||||
// AAudioStream_requestPause(audio_stream_);
|
||||
// AAudioStream_requestFlush(audio_stream_);
|
||||
// AAudioStream_requestStart(audio_stream_);
|
||||
// }
|
||||
|
||||
videoCodecFlushReq_ = true;
|
||||
audioCodecFlushReq_ = true;
|
||||
|
||||
// 6. 💡 [매우 중요] 마스터 시계 강제 업데이트
|
||||
// 이거 안 하면 비디오 스레드가 옛날 오디오 시간과 비교하느라 화면이 굳어버립니다.
|
||||
audioClock_ = targetSec;
|
||||
currentPosSec_ = targetSec;
|
||||
|
||||
seekReq_ = false;
|
||||
isAbsoluteSeek_ = false;
|
||||
|
||||
// 초기화가 끝났으니 다시 패킷을 처음부터 읽으러 올라갑니다.
|
||||
continue;
|
||||
}
|
||||
// 일시정지 상태거나 큐가 너무 꽉 찼다면 잠시 대기
|
||||
if (isPaused_ || (videoQueue_.getSizeBytes() + audioQueue_.getSizeBytes() > MAX_QUEUE_SIZE)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (av_read_frame(fmt_ctx_, pkt) < 0) {
|
||||
// EOF (파일 끝) 도달 시 대기
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pkt->stream_index == video_stream_idx_) {
|
||||
videoQueue_.push(pkt);
|
||||
} else if (pkt->stream_index == audio_stream_idx_) {
|
||||
audioQueue_.push(pkt);
|
||||
}
|
||||
av_packet_unref(pkt); // 큐 안에서 복사했으므로 원본은 비움
|
||||
}
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
|
||||
void PlayerEngine::audioThreadLoop() {
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
const int MIN_BUFFER_SIZE = 2 * 1024 * 1024;
|
||||
bool isBuffering = true;
|
||||
const int MAX_SONIC_SAMPLES = 8192;
|
||||
short* sonic_out_buf = new short[MAX_SONIC_SAMPLES * 2];
|
||||
|
||||
while (!abortRequest_) {
|
||||
if (isPaused_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
int currentAudioSize = audioQueue_.getSizeBytes();
|
||||
int currentVideoSize = videoQueue_.getSizeBytes();
|
||||
int totalQueueSize = currentAudioSize + currentVideoSize;
|
||||
|
||||
// 💡 배속 중이든 아니든 이제 무조건 정상적인 버퍼링 로직을 탑니다.
|
||||
if (totalQueueSize < MIN_BUFFER_SIZE / 2) isBuffering = true;
|
||||
else if (totalQueueSize >= MIN_BUFFER_SIZE) isBuffering = false;
|
||||
|
||||
if (isBuffering && !abortRequest_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
AVPacket* pkt = audioQueue_.pop();
|
||||
if (!pkt) break;
|
||||
|
||||
// 💡 [추가] 오디오도 스스로 코덱과 Sonic 버퍼를 비웁니다.
|
||||
if (audioCodecFlushReq_) {
|
||||
avcodec_flush_buffers(audio_codec_ctx_);
|
||||
|
||||
if (sonic_stream_) {
|
||||
sonicFlushStream(sonic_stream_);
|
||||
}
|
||||
|
||||
// AAudio의 틱 잡음을 막기 위해 재생 중인 버퍼도 비워줍니다.
|
||||
if (audio_stream_) {
|
||||
AAudioStream_requestPause(audio_stream_);
|
||||
AAudioStream_requestFlush(audio_stream_);
|
||||
AAudioStream_requestStart(audio_stream_);
|
||||
}
|
||||
audioCodecFlushReq_ = false;
|
||||
}
|
||||
|
||||
avcodec_send_packet(audio_codec_ctx_, pkt);
|
||||
while (avcodec_receive_frame(audio_codec_ctx_, frame) == 0) {
|
||||
|
||||
// 마스터 시계 갱신
|
||||
if (frame->pts != AV_NOPTS_VALUE) {
|
||||
audioClock_ = frame->pts * av_q2d(fmt_ctx_->streams[audio_stream_idx_]->time_base);
|
||||
}
|
||||
|
||||
if (swr_ctx_ && audio_stream_) {
|
||||
int out_samples = swr_get_out_samples(swr_ctx_, frame->nb_samples);
|
||||
uint8_t* out_buf = (uint8_t*)malloc(out_samples * 4); // S16 2채널 = 4바이트
|
||||
|
||||
// 1. FFmpeg으로 PCM 변환 (정배속 데이터)
|
||||
int converted = swr_convert(swr_ctx_, &out_buf, out_samples, (const uint8_t**)frame->data, frame->nb_samples);
|
||||
|
||||
if (converted > 0 && sonic_stream_ && !abortRequest_) {
|
||||
|
||||
// 🚀 2. 변환된 데이터를 Sonic 스트림에 밀어넣습니다 (입력)
|
||||
sonicWriteShortToStream(sonic_stream_, (short*)out_buf, converted);
|
||||
|
||||
// 🚀 3. Sonic 스트림에서 배속 처리 완료된 데이터를 뽑아냅니다 (출력)
|
||||
int samplesRead;
|
||||
do {
|
||||
// 가공된 데이터 꺼내기 (반환값: 꺼낸 샘플 수)
|
||||
samplesRead = sonicReadShortFromStream(sonic_stream_, sonic_out_buf, MAX_SONIC_SAMPLES);
|
||||
|
||||
if (samplesRead > 0 && !abortRequest_) {
|
||||
// 4. 가공된 최종 데이터를 사운드 카드(AAudio)에 씁니다!
|
||||
int32_t framesLeft = samplesRead;
|
||||
short* currentAAudioBuf = sonic_out_buf;
|
||||
|
||||
while (framesLeft > 0 && !abortRequest_) {
|
||||
int32_t framesWritten = AAudioStream_write(audio_stream_, currentAAudioBuf, framesLeft, 1000000000);
|
||||
if (seekReq_) break;
|
||||
if (framesWritten < 0) break;
|
||||
framesLeft -= framesWritten;
|
||||
currentAAudioBuf += framesWritten * 2; // 2채널 전진
|
||||
}
|
||||
}
|
||||
} while (samplesRead > 0); // Sonic에 꺼낼 데이터가 없을 때까지 반복
|
||||
}
|
||||
free(out_buf);
|
||||
}
|
||||
}
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
delete[] sonic_out_buf;
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
void PlayerEngine::videoThreadLoop() {
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
int last_win_w = 0, last_win_h = 0;
|
||||
|
||||
while (!abortRequest_) {
|
||||
if (isPaused_) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
AVPacket* pkt = videoQueue_.pop();
|
||||
if (!pkt) break;
|
||||
// 💡 [추가] 패킷을 밀어 넣기 직전에 청소 명령이 있었는지 확인!
|
||||
if (videoCodecFlushReq_) {
|
||||
avcodec_flush_buffers(video_codec_ctx_);
|
||||
videoCodecFlushReq_ = false;
|
||||
}
|
||||
|
||||
avcodec_send_packet(video_codec_ctx_, pkt);
|
||||
while (avcodec_receive_frame(video_codec_ctx_, frame) == 0) {
|
||||
|
||||
double videoPtsSec = frame->pts * av_q2d(fmt_ctx_->streams[video_stream_idx_]->time_base);
|
||||
currentPosSec_ = videoPtsSec; // UI 바 업데이트용
|
||||
|
||||
// 💡 위대한 귀환: 비디오는 무조건 오디오 시계만 쳐다봅니다!
|
||||
double delaySec = videoPtsSec - audioClock_.load();
|
||||
float currentSpeed = playbackSpeed_.load();
|
||||
|
||||
// 🚀 [A/V Sync & 프레임 드랍 로직]
|
||||
if (delaySec > 0.01) {
|
||||
// 비디오가 미래다 -> 남은 시간만큼 재운다
|
||||
double waitTime = delaySec / currentSpeed;
|
||||
std::this_thread::sleep_for(std::chrono::microseconds((int64_t)(waitTime * 1000000.0)));
|
||||
}
|
||||
else if (delaySec < -0.05) {
|
||||
// 비디오가 과거다 -> 그리지 않고 가차없이 버린다 (이것 덕분에 4배속 화면 렌더링 부하가 해결됨!)
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- 렌더링 통과 ---
|
||||
if (window_) {
|
||||
int w = ANativeWindow_getWidth(window_), h = ANativeWindow_getHeight(window_);
|
||||
if (!sws_ctx_ || w != last_win_w || h != last_win_h) {
|
||||
if (sws_ctx_) sws_freeContext(sws_ctx_);
|
||||
sws_ctx_ = sws_getContext(frame->width, frame->height, video_codec_ctx_->pix_fmt, w, h, AV_PIX_FMT_RGBA, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
last_win_w = w; last_win_h = h;
|
||||
}
|
||||
|
||||
ANativeWindow_Buffer buffer;
|
||||
if (ANativeWindow_lock(window_, &buffer, nullptr) == 0) {
|
||||
uint8_t* dst_data[4] = { (uint8_t*)buffer.bits, nullptr, nullptr, nullptr };
|
||||
int dst_line[4] = { buffer.stride * 4, 0, 0, 0 };
|
||||
if (sws_ctx_) sws_scale(sws_ctx_, frame->data, frame->linesize, 0, frame->height, dst_data, dst_line);
|
||||
ANativeWindow_unlockAndPost(window_);
|
||||
}
|
||||
}
|
||||
}
|
||||
av_packet_free(&pkt);
|
||||
}
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
std::string PlayerEngine::getSubtitleTracks() { return subtitle_tracks_info_; }
|
||||
void PlayerEngine::setSubtitleTrack(int streamIndex) { current_sub_stream_idx_ = streamIndex; }
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
#include "PacketQueue.h"
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <jni.h>
|
||||
#include <android/native_window.h>
|
||||
#include <aaudio/AAudio.h>
|
||||
#include "sonic.h" // 💡 Sonic 헤더 추가
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/channel_layout.h>
|
||||
}
|
||||
|
||||
class PlayerEngine {
|
||||
public:
|
||||
PlayerEngine(JavaVM* vm, jobject listenerObj);
|
||||
~PlayerEngine();
|
||||
|
||||
void setDataSource(int videoFd, int subtitleFd);
|
||||
void prepareAsync(); // 💡 비동기 준비 시작 함수
|
||||
void play(ANativeWindow* window);
|
||||
void pause();
|
||||
void stop();
|
||||
void seekBy(double seconds);
|
||||
void setSpeed(float speed);
|
||||
double getCurrentPosition() const { return currentPosSec_; }
|
||||
|
||||
std::string getSubtitleTracks();
|
||||
void setSubtitleTrack(int streamIndex);
|
||||
double getDuration() const;
|
||||
void seekTo(double seconds);
|
||||
|
||||
private:
|
||||
void readThreadLoop(); // 패킷을 읽어서 큐에 넣는 스레드 (생산자)
|
||||
void videoThreadLoop(); // 비디오 큐에서 꺼내서 렌더링하는 스레드 (소비자)
|
||||
void audioThreadLoop(); // 오디오 큐에서 꺼내서 출력하는 스레드 (소비자)
|
||||
|
||||
std::atomic<bool> videoCodecFlushReq_{false};
|
||||
std::atomic<bool> audioCodecFlushReq_{false};
|
||||
|
||||
PacketQueue videoQueue_;
|
||||
PacketQueue audioQueue_;
|
||||
|
||||
std::thread readThread_;
|
||||
std::thread videoThread_;
|
||||
std::thread audioThread_;
|
||||
|
||||
std::atomic<bool> abortRequest_{false};
|
||||
|
||||
// 💡 [A/V Sync의 핵심] 현재 오디오가 어디까지 재생되었는지 기록하는 마스터 시계
|
||||
std::atomic<double> audioClock_{0.0};
|
||||
|
||||
std::atomic<bool> isAbsoluteSeek_{false}; // 절대 위치 이동 여부 플래그
|
||||
std::atomic<double> seekTargetSec_{0.0};
|
||||
void prepareInternal(); // 💡 백그라운드 준비 스레드
|
||||
void renderLoop();
|
||||
void sendSubtitleToKotlin(const char* text);
|
||||
|
||||
int videoFd_ = -1;
|
||||
int subtitleFd_ = -1;
|
||||
|
||||
std::atomic<bool> isPrepared_{false};
|
||||
std::atomic<bool> isPlaying_{false};
|
||||
std::atomic<bool> isPaused_{false};
|
||||
|
||||
std::thread prepareThread_;
|
||||
std::thread renderThread_;
|
||||
ANativeWindow* window_ = nullptr;
|
||||
|
||||
std::atomic<bool> seekReq_{false};
|
||||
std::atomic<double> seekTargetOffset_{0.0};
|
||||
std::atomic<float> playbackSpeed_{1.0f};
|
||||
double currentPosSec_ = 0.0;
|
||||
|
||||
int current_sub_stream_idx_ = -1;
|
||||
std::string subtitle_tracks_info_;
|
||||
|
||||
AVFormatContext* fmt_ctx_ = nullptr;
|
||||
AVCodecContext* video_codec_ctx_ = nullptr;
|
||||
AVCodecContext* sub_codec_ctx_ = nullptr;
|
||||
AVCodecContext* audio_codec_ctx_ = nullptr;
|
||||
SwsContext* sws_ctx_ = nullptr;
|
||||
SwrContext* swr_ctx_ = nullptr;
|
||||
|
||||
int video_stream_idx_ = -1;
|
||||
int sub_stream_idx_ = -1;
|
||||
int audio_stream_idx_ = -1;
|
||||
|
||||
AAudioStream* audio_stream_ = nullptr;
|
||||
|
||||
JavaVM* jvm_ = nullptr;
|
||||
jobject listenerObj_ = nullptr;
|
||||
jmethodID subtitleMethodId_ = nullptr;
|
||||
jmethodID videoSizeMethodId_ = nullptr;
|
||||
jmethodID preparedMethodId_ = nullptr; // 💡 JNI 콜백 ID 추가
|
||||
jmethodID errorMethodId_ = nullptr; // 💡 JNI 에러 콜백 ID 추가
|
||||
|
||||
sonicStream sonic_stream_ = nullptr;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "Preloader.h"
|
||||
#include <android/log.h>
|
||||
|
||||
extern void callNextMediaCallback();
|
||||
|
||||
#define LOG_TAG "Preloader"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
Preloader::Preloader() : dataReady_(false), preloadFailed_(false) {}
|
||||
|
||||
Preloader::~Preloader() {
|
||||
releasePreloadedData();
|
||||
}
|
||||
|
||||
void Preloader::releasePreloadedData() {
|
||||
std::lock_guard<std::mutex> lock(preloadMutex_);
|
||||
nextMedia_.release();
|
||||
dataReady_ = false;
|
||||
preloadFailed_ = false;
|
||||
}
|
||||
|
||||
// [수정] std::string path 대신 int fd를 인자로 받음
|
||||
void Preloader::startNextPreload(int fd) {
|
||||
if (dataReady_) {
|
||||
LOGI("Preloader is busy with ready data. Ignoring new preload request.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
LOGE("Preloader received an invalid file descriptor.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 이전에 실패했더라도 새로운 요청이 오면 다시 시도하도록 초기화
|
||||
preloadFailed_ = false;
|
||||
|
||||
std::thread([this, fd]() {
|
||||
LOGI("Starting preload thread for media with fd: %d", fd);
|
||||
|
||||
MediaAsset tempMedia;
|
||||
if (tempMedia.load(fd)) {
|
||||
std::lock_guard<std::mutex> lock(preloadMutex_);
|
||||
nextMedia_ = std::move(tempMedia);
|
||||
dataReady_ = true;
|
||||
LOGI("Preloading finished successfully.");
|
||||
} else {
|
||||
// --- ⬇️ 실패 로그 추가 ⬇️ ---
|
||||
LOGE("!!! Preloading FAILED for fd: %d. !!!", fd);
|
||||
preloadFailed_ = true;
|
||||
callNextMediaCallback();
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
|
||||
bool Preloader::isPreloadedDataReady() const {
|
||||
return dataReady_;
|
||||
}
|
||||
|
||||
bool Preloader::hasPreloadFailed() const {
|
||||
return preloadFailed_;
|
||||
}
|
||||
|
||||
MediaAsset Preloader::swapAndRelease() {
|
||||
std::lock_guard<std::mutex> lock(preloadMutex_);
|
||||
if (dataReady_) {
|
||||
dataReady_ = false;
|
||||
preloadFailed_ = false;
|
||||
return std::move(nextMedia_);
|
||||
}
|
||||
return MediaAsset(); // 준비되지 않았으면 빈 MediaAsset 반환
|
||||
}
|
||||
|
||||
void Preloader::setPreloadedMedia(MediaAsset&& media) {
|
||||
std::lock_guard<std::mutex> lock(preloadMutex_);
|
||||
nextMedia_ = std::move(media);
|
||||
dataReady_ = true;
|
||||
preloadFailed_ = false;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "MediaAsset.h"
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
class Preloader {
|
||||
public:
|
||||
Preloader();
|
||||
~Preloader();
|
||||
void startNextPreload(int fd); // [수정] string -> int
|
||||
bool isPreloadedDataReady() const;
|
||||
bool hasPreloadFailed() const;
|
||||
MediaAsset swapAndRelease();
|
||||
void setPreloadedMedia(MediaAsset&& media);
|
||||
void releasePreloadedData();
|
||||
|
||||
private:
|
||||
std::mutex preloadMutex_;
|
||||
MediaAsset nextMedia_;
|
||||
std::atomic<bool> dataReady_;
|
||||
std::atomic<bool> preloadFailed_;
|
||||
};
|
||||
@@ -0,0 +1,523 @@
|
||||
#include "Renderer.h"
|
||||
#include "AnimationStrategy.cpp"
|
||||
#include "AnimationStrategy.h"
|
||||
#include "TransitionStrategy.cpp"
|
||||
#include <android/log.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
extern void callNextMediaCallback();
|
||||
|
||||
#define LOG_TAG "Renderer"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
// ====================================================================
|
||||
// 생성자, 소멸자 및 설정(Setter) 함수들
|
||||
// ====================================================================
|
||||
Renderer::Renderer() {
|
||||
randomEngine_.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
setAnimationMode(static_cast<int>(AnimationMode::PAN));
|
||||
setTransitionMode(static_cast<int>(TransitionMode::FADE));
|
||||
}
|
||||
Renderer::~Renderer() {
|
||||
stopRenderLoop();
|
||||
release();
|
||||
}
|
||||
void Renderer::release() { std::lock_guard<std::mutex> lock(renderMutex_); currentMedia_.release(); nextMedia_.release(); }
|
||||
void Renderer::setNextMedia(int fd) { preloader_.startNextPreload(fd); }
|
||||
void Renderer::setAnimationSpeed(float speed) { animationSpeed_ = speed > 0 ? speed : 1.0f; }
|
||||
void Renderer::setFadeDuration(int durationMs) { fadeDurationMs_ = durationMs > 0 ? durationMs : 3000; }
|
||||
void Renderer::setPageTurnDelay(int delayMs) { pageTurnDelayMs_ = delayMs > 0 ? delayMs : 5000; }
|
||||
|
||||
void Renderer::setAnimationMode(int mode) {
|
||||
configuredAnimationMode_ = (mode >= 0 && mode <= static_cast<int>(AnimationMode::PAGE_TURN)) ? static_cast<AnimationMode>(mode) : AnimationMode::PAN;
|
||||
determineActiveAnimationMode();
|
||||
}
|
||||
void Renderer::setTransitionMode(int mode) {
|
||||
configuredTransitionMode_ = (mode >= 0 && mode <= static_cast<int>(TransitionMode::MOSAIC)) ? static_cast<TransitionMode>(mode) : TransitionMode::FADE;
|
||||
}
|
||||
|
||||
void Renderer::startRenderLoop(ANativeWindow* window) {
|
||||
if (isRunning_) return; // 이미 실행 중이면 무시
|
||||
|
||||
nativeWindow_ = window;
|
||||
if (nativeWindow_) {
|
||||
ANativeWindow_acquire(nativeWindow_);
|
||||
isRunning_ = true;
|
||||
renderThread_ = std::thread([this]() {
|
||||
LOGI("C++ Render thread started.");
|
||||
while (isRunning_) {
|
||||
auto frameStartTime = std::chrono::steady_clock::now();
|
||||
|
||||
renderFrame(nativeWindow_); // 기존의 복잡한 renderFrame 함수를 그대로 호출
|
||||
|
||||
auto frameEndTime = std::chrono::steady_clock::now();
|
||||
auto frameDuration = std::chrono::duration_cast<std::chrono::milliseconds>(frameEndTime - frameStartTime);
|
||||
|
||||
// --- ⬇️ 수정: 고정 딜레이 -> 가변 딜레이 ⬇️ ---
|
||||
// 현재 설정된 목표 딜레이(currentFrameDelay_)에 맞춰 대기
|
||||
auto sleepTime = currentFrameDelay_ - frameDuration;
|
||||
if (sleepTime > std::chrono::milliseconds(0)) {
|
||||
std::this_thread::sleep_for(sleepTime);
|
||||
}
|
||||
}
|
||||
LOGI("C++ Render thread finished.");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::stopRenderLoop() {
|
||||
if (!isRunning_) return;
|
||||
|
||||
isRunning_ = false;
|
||||
if (renderThread_.joinable()) {
|
||||
renderThread_.join();
|
||||
}
|
||||
if (nativeWindow_) {
|
||||
ANativeWindow_release(nativeWindow_);
|
||||
nativeWindow_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::determineActiveAnimationMode() {
|
||||
AnimationMode modeToSetActive;
|
||||
if (configuredAnimationMode_ == AnimationMode::RANDOM) {
|
||||
static const std::vector<AnimationMode> availableModes = { AnimationMode::PAN, AnimationMode::ZOOM, AnimationMode::NONE, AnimationMode::PAN_ONE_WAY, AnimationMode::PAGE_TURN };
|
||||
std::uniform_int_distribution<size_t> dist(0, availableModes.size() - 1);
|
||||
modeToSetActive = availableModes[dist(randomEngine_)];
|
||||
} else {
|
||||
modeToSetActive = configuredAnimationMode_;
|
||||
}
|
||||
activeAnimationMode_ = modeToSetActive;
|
||||
switch (activeAnimationMode_) {
|
||||
case AnimationMode::PAN: animationStrategy_ = std::make_unique<PanAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::PAN_ONE_WAY: animationStrategy_ = std::make_unique<PanOneWayAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::ZOOM: animationStrategy_ = std::make_unique<ZoomAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::PAGE_TURN: animationStrategy_ = std::make_unique<PageTurnAnimation>(animationSpeed_, pageTurnDelayMs_); break;
|
||||
case AnimationMode::NONE: default: animationStrategy_ = std::make_unique<NoneAnimation>(animationSpeed_); break;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 상태 머신(State Machine) 핸들러 함수들
|
||||
// ====================================================================
|
||||
|
||||
void Renderer::handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight) {
|
||||
if (!animationStrategy_) return;
|
||||
|
||||
bool isCycleComplete = animationStrategy_->execute(this, buffer, currentMedia_, surfaceWidth, surfaceHeight);
|
||||
|
||||
if ((isCycleComplete || forceNextFlag_) && nextMedia_.isValid()) {
|
||||
forceNextFlag_ = false; // 플래그 초기화
|
||||
lastAnimationState_ = animationStrategy_->getState();
|
||||
predictedNextAnimationMode_ = predictNextAnimationMode();
|
||||
currentState_ = RenderState::TRANSITIONING;
|
||||
transitionStartTime_ = std::chrono::steady_clock::now();
|
||||
|
||||
TransitionMode transModeToUse = configuredTransitionMode_;
|
||||
if (transModeToUse == TransitionMode::RANDOM) {
|
||||
std::uniform_int_distribution<int> dist(0, 2);
|
||||
transModeToUse = static_cast<TransitionMode>(dist(randomEngine_));
|
||||
}
|
||||
if (transModeToUse == TransitionMode::SLIDE) {
|
||||
transitionStrategy_ = std::make_unique<SlideTransition>(fadeDurationMs_, surfaceWidth);
|
||||
} else if (transModeToUse == TransitionMode::MOSAIC) {
|
||||
transitionStrategy_ = std::make_unique<MosaicTransition>(fadeDurationMs_, 20, 32, randomEngine_);
|
||||
} else {
|
||||
transitionStrategy_ = std::make_unique<FadeTransition>(fadeDurationMs_);
|
||||
}
|
||||
if(transitionStrategy_) transitionStrategy_->reset();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 다음에 실행될 애니메이션 모드를 미리 예측하여 반환합니다.
|
||||
*/
|
||||
Renderer::AnimationMode Renderer::predictNextAnimationMode() {
|
||||
if (configuredAnimationMode_ == AnimationMode::RANDOM) {
|
||||
static const std::vector<AnimationMode> availableModes = {
|
||||
AnimationMode::PAN, AnimationMode::ZOOM, AnimationMode::NONE,
|
||||
AnimationMode::PAN_ONE_WAY, AnimationMode::PAGE_TURN
|
||||
};
|
||||
std::uniform_int_distribution<size_t> dist(0, availableModes.size() - 1);
|
||||
return availableModes[dist(randomEngine_)];
|
||||
} else {
|
||||
return configuredAnimationMode_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 주어진 애니메이션 모드의 시작 상태(좌표, 스케일)를 계산하여 반환합니다.
|
||||
*/
|
||||
AnimationState Renderer::getStartStateForMode(AnimationMode mode, int surfaceWidth, int surfaceHeight) {
|
||||
AnimationState startState;
|
||||
if (mode == AnimationMode::PAN || mode == AnimationMode::PAN_ONE_WAY) {
|
||||
// Pan 계열은 가장자리(0,0)에서 시작
|
||||
startState.offsetX = 0.0f;
|
||||
startState.offsetY = 0.0f;
|
||||
|
||||
// Pan 계열의 기본 스케일 계산
|
||||
float scale;
|
||||
if ((static_cast<float>(nextMedia_.getWidth()) / nextMedia_.getHeight()) > ((float)surfaceWidth / surfaceHeight)) {
|
||||
scale = (float)surfaceHeight / nextMedia_.getHeight();
|
||||
} else {
|
||||
scale = (float)surfaceWidth / nextMedia_.getWidth();
|
||||
}
|
||||
startState.scale = scale;
|
||||
|
||||
} else {
|
||||
// Zoom, None, PageTurn 등은 중앙 정렬에서 시작
|
||||
float baseScale, baseOffsetX, baseOffsetY;
|
||||
calculateFitScaleAndOffset(nextMedia_, surfaceWidth, surfaceHeight, baseScale, baseOffsetX, baseOffsetY);
|
||||
startState.offsetX = baseOffsetX;
|
||||
startState.offsetY = baseOffsetY;
|
||||
startState.scale = baseScale;
|
||||
}
|
||||
return startState;
|
||||
}
|
||||
|
||||
void Renderer::handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight) {
|
||||
|
||||
if (!transitionStrategy_ || !nextMedia_.isValid()) {
|
||||
currentState_ = RenderState::ANIMATING;
|
||||
if(animationStrategy_) animationStrategy_->reset();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 2. 해당 모드의 전문가를 "임시로" 고용하여 시작 상태가 어떨지 물어봅니다.
|
||||
std::unique_ptr<AnimationStrategy> tempNextStrategy;
|
||||
switch (predictedNextAnimationMode_) {
|
||||
case AnimationMode::PAN:
|
||||
tempNextStrategy = std::make_unique<PanAnimation>(animationSpeed_);
|
||||
break;
|
||||
case AnimationMode::PAN_ONE_WAY:
|
||||
tempNextStrategy = std::make_unique<PanOneWayAnimation>(animationSpeed_);
|
||||
break;
|
||||
case AnimationMode::ZOOM:
|
||||
tempNextStrategy = std::make_unique<ZoomAnimation>(animationSpeed_);
|
||||
break;
|
||||
case AnimationMode::PAGE_TURN:
|
||||
tempNextStrategy = std::make_unique<PageTurnAnimation>(animationSpeed_, pageTurnDelayMs_);
|
||||
break;
|
||||
case AnimationMode::NONE:
|
||||
default:
|
||||
tempNextStrategy = std::make_unique<NoneAnimation>(animationSpeed_);
|
||||
break;
|
||||
}
|
||||
|
||||
AnimationState destStartState;
|
||||
if (tempNextStrategy) {
|
||||
destStartState = tempNextStrategy->getStartState(this, nextMedia_, surfaceWidth, surfaceHeight);
|
||||
}
|
||||
|
||||
// 3. 전환 전문가에게 모든 정보를 (이전 상태의 끝, 다음 상태의 시작) 넘겨주고 그리기를 위임
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
long long elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - transitionStartTime_).count();
|
||||
bool isComplete = transitionStrategy_->execute(this, buffer, currentMedia_, lastAnimationState_, nextMedia_, destStartState, elapsed);
|
||||
|
||||
// 4. 상태 전환 체크
|
||||
if (isComplete) {
|
||||
currentMedia_ = std::move(nextMedia_);
|
||||
currentState_ = RenderState::ANIMATING;
|
||||
// 예측했던 모드를 실제로 적용
|
||||
activeAnimationMode_ = predictedNextAnimationMode_;
|
||||
switch (activeAnimationMode_) { // 해당 전략 객체 생성
|
||||
case AnimationMode::PAN: animationStrategy_ = std::make_unique<PanAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::PAN_ONE_WAY: animationStrategy_ = std::make_unique<PanOneWayAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::ZOOM: animationStrategy_ = std::make_unique<ZoomAnimation>(animationSpeed_); break;
|
||||
case AnimationMode::PAGE_TURN: animationStrategy_ = std::make_unique<PageTurnAnimation>(animationSpeed_, pageTurnDelayMs_); break;
|
||||
case AnimationMode::NONE:
|
||||
default: animationStrategy_ = std::make_unique<NoneAnimation>(animationSpeed_);
|
||||
break;
|
||||
}
|
||||
if(animationStrategy_) animationStrategy_->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::updateWeatherBitmap(void* pixels, int width, int height) {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
weatherWidth_ = width;
|
||||
weatherHeight_ = height;
|
||||
|
||||
size_t size = static_cast<size_t>(width * height * 4);
|
||||
weatherPixels_.assign(static_cast<uint8_t*>(pixels), static_cast<uint8_t*>(pixels) + size);
|
||||
|
||||
}
|
||||
|
||||
void Renderer::clearWeatherBitmap() {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
weatherPixels_.clear();
|
||||
}
|
||||
|
||||
void Renderer::setImageRenderFrame(int frame) {
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
imageFrame_ = frame;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 메인 렌더링 루프 (교통정리 담당)
|
||||
// ====================================================================
|
||||
void Renderer::renderFrame(ANativeWindow* window) {
|
||||
if (!window) return;
|
||||
std::lock_guard<std::mutex> lock(renderMutex_);
|
||||
|
||||
if (!currentMedia_.isValid() && preloader_.isPreloadedDataReady()) {
|
||||
currentMedia_ = preloader_.swapAndRelease();
|
||||
if (currentMedia_.isValid()) {
|
||||
// --- ⬇️ 프레임 딜레이 설정 로직 추가 ⬇️ ---
|
||||
if (currentMedia_.getType() == MediaAsset::Type::VIDEO && currentMedia_.getFps() > 0) {
|
||||
currentFrameDelay_ = std::chrono::milliseconds(static_cast<long long>(1000.0 / currentMedia_.getFps()));
|
||||
LOGI("Media type: Video. Frame delay set to %lldms for %.2f FPS", currentFrameDelay_.count(), currentMedia_.getFps());
|
||||
} else {
|
||||
currentFrameDelay_ = std::chrono::milliseconds(imageFrame_); // 이미지일 경우 30fps
|
||||
LOGI("Media type: Image. Frame delay set to 33ms (~30 FPS)");
|
||||
}
|
||||
currentState_ = RenderState::ANIMATING;
|
||||
determineActiveAnimationMode();
|
||||
if(animationStrategy_) animationStrategy_->reset();
|
||||
callNextMediaCallback();
|
||||
}
|
||||
}
|
||||
if (!currentMedia_.isValid()) {
|
||||
ANativeWindow_Buffer buffer;
|
||||
if (ANativeWindow_lock(window, &buffer, nullptr) == 0) {
|
||||
memset(buffer.bits, 0, buffer.stride * buffer.height * sizeof(uint32_t));
|
||||
ANativeWindow_unlockAndPost(window);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!nextMedia_.isValid() && preloader_.isPreloadedDataReady()) {
|
||||
nextMedia_ = preloader_.swapAndRelease();
|
||||
if(nextMedia_.isValid()) { callNextMediaCallback(); }
|
||||
}
|
||||
|
||||
ANativeWindow_Buffer buffer;
|
||||
if (ANativeWindow_lock(window, &buffer, nullptr) != 0) return;
|
||||
int surfaceWidth = ANativeWindow_getWidth(window);
|
||||
int surfaceHeight = ANativeWindow_getHeight(window);
|
||||
|
||||
switch (currentState_) {
|
||||
case RenderState::ANIMATING:
|
||||
handleAnimationState(buffer, surfaceWidth, surfaceHeight);
|
||||
break;
|
||||
case RenderState::TRANSITIONING:
|
||||
handleTransitionState(buffer, surfaceWidth, surfaceHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(weatherMutex_);
|
||||
if (!weatherPixels_.empty()) {
|
||||
// ======== ⬇️ 유기적인 움직임(Drift) 추가 ⬇️ ========
|
||||
std::uniform_real_distribution<float> driftDist(-0.3f, 0.3f); // 방향 전환 폭을 살짝 키움
|
||||
weatherVelX_ += driftDist(randomEngine_);
|
||||
weatherVelY_ += driftDist(randomEngine_);
|
||||
|
||||
// 2. 현재 속도(벡터의 길이) 계산
|
||||
float speed = std::sqrt(weatherVelX_ * weatherVelX_ + weatherVelY_ * weatherVelY_);
|
||||
|
||||
// 💡 여기서 최소/최대 이동 픽셀을 강제로 지정합니다.
|
||||
float maxSpeed = 3.0f; // 프레임당 최대 5픽셀 이동 (답답하지 않게 상향)
|
||||
float minSpeed = 1.0f; // 프레임당 최소 2픽셀 이동 보장 (절대 멈추거나 느려지지 않음)
|
||||
|
||||
// 속도 보정 (Normalization & Scaling)
|
||||
if (speed < 0.001f) {
|
||||
// 완전히 멈췄을 때의 방어 코드
|
||||
weatherVelX_ = minSpeed;
|
||||
weatherVelY_ = minSpeed;
|
||||
} else if (speed > maxSpeed) {
|
||||
// 한계 속도 초과 시 maxSpeed로 깎아냄
|
||||
weatherVelX_ = (weatherVelX_ / speed) * maxSpeed;
|
||||
weatherVelY_ = (weatherVelY_ / speed) * maxSpeed;
|
||||
} else if (speed < minSpeed) {
|
||||
// 🚀 속도가 너무 줄어들면 강제로 최소 속도(minSpeed) 픽셀만큼 끌어올림
|
||||
weatherVelX_ = (weatherVelX_ / speed) * minSpeed;
|
||||
weatherVelY_ = (weatherVelY_ / speed) * minSpeed;
|
||||
}
|
||||
|
||||
// 3. 위치 업데이트 (최소 2px ~ 최대 5px 이동 보장)
|
||||
weatherX_ += weatherVelX_;
|
||||
weatherY_ += weatherVelY_;
|
||||
|
||||
// 4. 화면 경계 검사 및 튕기기 (Bounce)
|
||||
// 튕길 때 속도가 너무 크게 변하지 않도록 난수 폭을 안정적으로(0.9~1.1) 조절
|
||||
std::uniform_real_distribution<float> bounceDist(0.9f, 1.1f);
|
||||
|
||||
// 가로 경계
|
||||
if (weatherX_ < 0) {
|
||||
weatherX_ = 0;
|
||||
weatherVelX_ = std::abs(weatherVelX_) * bounceDist(randomEngine_);
|
||||
} else if (weatherX_ + weatherWidth_ > surfaceWidth) {
|
||||
weatherX_ = (float)surfaceWidth - weatherWidth_;
|
||||
weatherVelX_ = -std::abs(weatherVelX_) * bounceDist(randomEngine_);
|
||||
}
|
||||
|
||||
// 세로 경계
|
||||
if (weatherY_ < 0) {
|
||||
weatherY_ = 0;
|
||||
weatherVelY_ = std::abs(weatherVelY_) * bounceDist(randomEngine_);
|
||||
} else if (weatherY_ + weatherHeight_ > surfaceHeight) {
|
||||
weatherY_ = (float)surfaceHeight - weatherHeight_;
|
||||
weatherVelY_ = -std::abs(weatherVelY_) * bounceDist(randomEngine_);
|
||||
}
|
||||
|
||||
// 3. 그리기 (기존의 블렌딩 로직 사용)
|
||||
uint32_t* dstPixels = (uint32_t*)buffer.bits;
|
||||
int dstStride = buffer.stride;
|
||||
|
||||
for (int y = 0; y < weatherHeight_; ++y) {
|
||||
int targetY = static_cast<int>(weatherY_) + y;
|
||||
if (targetY < 0 || targetY >= surfaceHeight) continue;
|
||||
|
||||
for (int x = 0; x < weatherWidth_; ++x) {
|
||||
int targetX = static_cast<int>(weatherX_) + x;
|
||||
if (targetX < 0 || targetX >= surfaceWidth) continue;
|
||||
|
||||
const uint8_t* src = &weatherPixels_[(y * weatherWidth_ + x) * 4];
|
||||
uint8_t alpha = src[3];
|
||||
if (alpha == 0) continue;
|
||||
|
||||
uint32_t* dst = &dstPixels[targetY * dstStride + targetX];
|
||||
|
||||
// ======== ⬇️ 이 부분을 수정합니다 ⬇️ ========
|
||||
// Red와 Blue 채널의 비트 시프트(Shift) 위치를 안드로이드 Bitmap(RGBA) 규격에 맞게 수정
|
||||
uint8_t dr = (*dst) & 0xFF; // 배경의 Red
|
||||
uint8_t dg = (*dst >> 8) & 0xFF; // 배경의 Green
|
||||
uint8_t db = (*dst >> 16) & 0xFF; // 배경의 Blue
|
||||
|
||||
// 날씨 아이콘(src)의 R(0), G(1), B(2)와 배경(dst)을 알파 블렌딩
|
||||
uint8_t r = (src[0] * alpha + dr * (255 - alpha)) / 255;
|
||||
uint8_t g = (src[1] * alpha + dg * (255 - alpha)) / 255;
|
||||
uint8_t b = (src[2] * alpha + db * (255 - alpha)) / 255;
|
||||
|
||||
*dst = (0xFF << 24) | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ANativeWindow_unlockAndPost(window);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 하위 그리기 함수 및 헬퍼 함수들
|
||||
// ====================================================================
|
||||
void Renderer::drawMedia(ANativeWindow_Buffer& buffer, MediaAsset& media, float alpha, float finalOffsetX, float finalOffsetY, float finalScale) {
|
||||
if (!media.isValid() || alpha <= 0.0f) return;
|
||||
if (media.getType() == MediaAsset::Type::IMAGE) {
|
||||
renderImageFrame(media, buffer, finalScale, finalOffsetX, finalOffsetY, alpha);
|
||||
} else {
|
||||
renderVideoFrame(media, buffer, finalScale, finalOffsetX, finalOffsetY, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderImageFrame(const MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha) {
|
||||
uint32_t* dstPixels = (uint32_t*)buffer.bits;
|
||||
int dstStride = buffer.stride;
|
||||
const uint8_t* pixelData = media.getType() == MediaAsset::Type::IMAGE ? media.getImageData() : media.getRgbBuffer().data();
|
||||
if (!pixelData) return;
|
||||
|
||||
int imgW = media.getWidth();
|
||||
int imgH = media.getHeight();
|
||||
uint8_t alphaByte = static_cast<uint8_t>(alpha * 255.0f);
|
||||
|
||||
for (int y = 0; y < buffer.height; ++y) {
|
||||
int srcY = static_cast<int>((y - offsetY) / scale);
|
||||
if (srcY < 0 || srcY >= imgH) continue;
|
||||
uint32_t* dstRow = dstPixels + y * dstStride;
|
||||
for (int x = 0; x < buffer.width; ++x) {
|
||||
int srcX = static_cast<int>((x - offsetX) / scale);
|
||||
if (srcX < 0 || srcX >= imgW) continue;
|
||||
const uint8_t* srcPixel = &pixelData[(srcY * imgW + srcX) * 4];
|
||||
uint32_t dstPixelValue = dstRow[x];
|
||||
uint8_t dstB = (dstPixelValue >> 0) & 0xFF;
|
||||
uint8_t dstG = (dstPixelValue >> 8) & 0xFF;
|
||||
uint8_t dstR = (dstPixelValue >> 16) & 0xFF;
|
||||
uint8_t finalR = (srcPixel[0] * alphaByte + dstR * (255 - alphaByte)) / 255;
|
||||
uint8_t finalG = (srcPixel[1] * alphaByte + dstG * (255 - alphaByte)) / 255;
|
||||
uint8_t finalB = (srcPixel[2] * alphaByte + dstB * (255 - alphaByte)) / 255;
|
||||
dstRow[x] = (0xFF << 24) | (finalR << 16) | (finalG << 8) | finalB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderVideoFrame(MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha) {
|
||||
AVFormatContext* fmt_ctx = media.getFormatContext();
|
||||
AVCodecContext* codec_ctx = media.getCodecContext();
|
||||
AVFrame* frame = media.getFrame();
|
||||
AVPacket* pkt = media.getPacket();
|
||||
SwsContext* sws_ctx = media.getSwsContext();
|
||||
int video_stream_idx = media.getVideoStreamIndex();
|
||||
|
||||
if (!fmt_ctx || !codec_ctx || !frame || !pkt || !sws_ctx) return;
|
||||
|
||||
int ret = av_read_frame(fmt_ctx, pkt);
|
||||
if (ret >= 0) {
|
||||
if (pkt->stream_index == video_stream_idx) {
|
||||
if (avcodec_send_packet(codec_ctx, pkt) >= 0) {
|
||||
if (avcodec_receive_frame(codec_ctx, frame) == 0) {
|
||||
std::vector<uint8_t>& rgbBuf = media.getRgbBuffer();
|
||||
uint8_t* dst[4] = { rgbBuf.data(), nullptr, nullptr, nullptr };
|
||||
int dstStride_arr[4] = { media.getWidth() * 4, 0, 0, 0 };
|
||||
sws_scale(sws_ctx, frame->data, frame->linesize, 0, media.getHeight(), dst, dstStride_arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
av_packet_unref(pkt);
|
||||
} else if (ret == AVERROR_EOF) {
|
||||
av_seek_frame(fmt_ctx, video_stream_idx, 0, AVSEEK_FLAG_BACKWARD);
|
||||
}
|
||||
|
||||
renderImageFrame(media, buffer, scale, offsetX, offsetY, alpha);
|
||||
}
|
||||
|
||||
void Renderer::calculateFitScaleAndOffset(const MediaAsset& media, int surfaceWidth, int surfaceHeight, float& outScale, float& outOffsetX, float& outOffsetY) const {
|
||||
if (!media.isValid() || media.getWidth() == 0 || media.getHeight() == 0) {
|
||||
outScale = 1.0f; outOffsetX = 0.0f; outOffsetY = 0.0f;
|
||||
return;
|
||||
}
|
||||
float mediaAspect = static_cast<float>(media.getWidth()) / media.getHeight();
|
||||
float surfaceAspect = static_cast<float>(surfaceWidth) / surfaceHeight;
|
||||
if (mediaAspect > surfaceAspect) {
|
||||
outScale = static_cast<float>(surfaceHeight) / media.getHeight();
|
||||
outOffsetX = (static_cast<float>(surfaceWidth) - (media.getWidth() * outScale)) / 2.0f;
|
||||
outOffsetY = 0.0f;
|
||||
} else {
|
||||
outScale = static_cast<float>(surfaceWidth) / media.getWidth();
|
||||
outOffsetX = 0.0f;
|
||||
outOffsetY = (static_cast<float>(surfaceHeight) - (media.getHeight() * outScale)) / 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 현재 렌더러의 내부 상태를 문자열로 반환합니다. (디버깅용)
|
||||
*/
|
||||
std::string Renderer::getDebugInfo() const {
|
||||
std::stringstream ss;
|
||||
ss << "========== Native State ==========\n";
|
||||
ss << " Configured Anim: " << static_cast<int>(configuredAnimationMode_) << "\n";
|
||||
ss << " Active Anim : " << static_cast<int>(activeAnimationMode_) << "\n";
|
||||
ss << " Configured Trans: " << static_cast<int>(configuredTransitionMode_) << "\n";
|
||||
ss << " In CurrentState: " << static_cast<int>(currentState_) << "\n";
|
||||
|
||||
if (currentMedia_.isValid()) {
|
||||
ss << " Current Media: VALID ["
|
||||
<< (currentMedia_.getType() == MediaAsset::Type::IMAGE ? "Image" : "Video")
|
||||
<< " " << currentMedia_.getWidth() << "x" << currentMedia_.getHeight() << "]\n";
|
||||
} else {
|
||||
ss << " Current Media: INVALID\n";
|
||||
}
|
||||
|
||||
if (nextMedia_.isValid()) {
|
||||
ss << " Next Media : VALID ["
|
||||
<< (nextMedia_.getType() == MediaAsset::Type::IMAGE ? "Image" : "Video")
|
||||
<< " " << nextMedia_.getWidth() << "x" << nextMedia_.getHeight() << "]";
|
||||
} else {
|
||||
ss << " Next Media : INVALID";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "AnimationStrategy.h"
|
||||
#include "TransitionStrategy.h"
|
||||
#include "Preloader.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <memory>
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
enum class AnimationMode {
|
||||
PAN = 0, ZOOM = 1, NONE = 2, RANDOM = 3,
|
||||
PAN_ONE_WAY = 4, PAGE_TURN = 5
|
||||
};
|
||||
enum class TransitionMode {
|
||||
FADE = 0, SLIDE = 1, RANDOM = 2, MOSAIC = 3
|
||||
};
|
||||
|
||||
Renderer();
|
||||
~Renderer();
|
||||
|
||||
void setNextMedia(int fd);
|
||||
void renderFrame(ANativeWindow* window);
|
||||
void release();
|
||||
std::string getDebugInfo() const;
|
||||
|
||||
void startRenderLoop(ANativeWindow* window);
|
||||
void stopRenderLoop();
|
||||
bool forceNextFlag_ = false;
|
||||
|
||||
// 공개 메서드 추가
|
||||
void forceNext() { forceNextFlag_ = true; }
|
||||
void setAnimationSpeed(float speed);
|
||||
void setAnimationMode(int mode);
|
||||
void setFadeDuration(int durationMs);
|
||||
void setPageTurnDelay(int delayMs);
|
||||
void setTransitionMode(int mode);
|
||||
void setImageRenderFrame(int frame);
|
||||
void updateWeatherBitmap(void* pixels, int width, int height);
|
||||
void clearWeatherBitmap();
|
||||
void drawMedia(ANativeWindow_Buffer& buffer, MediaAsset& media, float alpha, float finalOffsetX, float finalOffsetY, float finalScale);
|
||||
void renderVideoFrame(MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha);
|
||||
void renderImageFrame(const MediaAsset& media, ANativeWindow_Buffer& buffer, float scale, float offsetX, float offsetY, float alpha);
|
||||
void calculateFitScaleAndOffset(const MediaAsset& media, int surfaceWidth, int surfaceHeight,
|
||||
float& outScale, float& outOffsetX, float& outOffsetY) const;
|
||||
|
||||
private:
|
||||
|
||||
std::thread renderThread_;
|
||||
std::atomic<bool> isRunning_{false};
|
||||
ANativeWindow* nativeWindow_ = nullptr;
|
||||
|
||||
enum class RenderState { ANIMATING, TRANSITIONING };
|
||||
RenderState currentState_ = RenderState::ANIMATING;
|
||||
|
||||
void handleAnimationState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
||||
void handleTransitionState(ANativeWindow_Buffer& buffer, int surfaceWidth, int surfaceHeight);
|
||||
|
||||
std::mutex renderMutex_;
|
||||
Preloader preloader_;
|
||||
MediaAsset currentMedia_;
|
||||
MediaAsset nextMedia_;
|
||||
|
||||
std::unique_ptr<AnimationStrategy> animationStrategy_;
|
||||
AnimationMode predictedNextAnimationMode_;
|
||||
std::unique_ptr<TransitionStrategy> transitionStrategy_;
|
||||
AnimationState lastAnimationState_;
|
||||
|
||||
AnimationMode configuredAnimationMode_ = AnimationMode::PAN;
|
||||
TransitionMode configuredTransitionMode_ = TransitionMode::FADE;
|
||||
AnimationMode activeAnimationMode_ = AnimationMode::PAN;
|
||||
long long fadeDurationMs_ = 3000;
|
||||
long long pageTurnDelayMs_ = 5000;
|
||||
float animationSpeed_ = 1.0f;
|
||||
// --- ⬇️ 목표 프레임 딜레이 변수 추가 ⬇️ ---
|
||||
std::chrono::milliseconds currentFrameDelay_{33}; // 기본값 33ms (약 30fps)
|
||||
|
||||
AnimationState getStartStateForMode(AnimationMode mode, int surfaceWidth, int surfaceHeight);
|
||||
AnimationMode predictNextAnimationMode();
|
||||
|
||||
std::chrono::steady_clock::time_point transitionStartTime_;
|
||||
std::mt19937 randomEngine_;
|
||||
|
||||
void determineActiveAnimationMode();
|
||||
|
||||
|
||||
std::vector<uint8_t> weatherPixels_;
|
||||
int weatherWidth_ = 0;
|
||||
int weatherHeight_ = 0;
|
||||
int imageFrame_ = 33;
|
||||
// 위치 변수
|
||||
float weatherX_ = 100.0f;
|
||||
float weatherY_ = 100.0f;
|
||||
|
||||
// 속도 변수 (방향 및 속도 조절)
|
||||
float weatherVelX_ = 2.5f;
|
||||
float weatherVelY_ = 2.0f;
|
||||
|
||||
std::mutex weatherMutex_;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,141 @@
|
||||
#include "TransitionStrategy.h"
|
||||
#include "Renderer.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
|
||||
// ====================================================================
|
||||
// --- 페이드 전환 효과 ---
|
||||
// ====================================================================
|
||||
class FadeTransition : public TransitionStrategy {
|
||||
public:
|
||||
FadeTransition(long long duration) : TransitionStrategy(duration) {}
|
||||
void reset() override {}
|
||||
bool isComplete(long long elapsedMs) const override { return elapsedMs >= durationMs_; }
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer,
|
||||
MediaAsset& source, const AnimationState& sourceEnd,
|
||||
MediaAsset& dest, const AnimationState& destStart,
|
||||
long long elapsedMs) override {
|
||||
|
||||
float progress = std::clamp((float)elapsedMs / durationMs_, 0.0f, 1.0f);
|
||||
|
||||
// source는 전달받은 마지막 상태(sourceEnd) 그대로 페이드 아웃
|
||||
renderer->drawMedia(buffer, source, 1.0f - progress, sourceEnd.offsetX, sourceEnd.offsetY, sourceEnd.scale);
|
||||
// dest는 전달받은 시작 상태(destStart) 그대로 페이드 인
|
||||
renderer->drawMedia(buffer, dest, progress, destStart.offsetX, destStart.offsetY, destStart.scale);
|
||||
|
||||
return isComplete(elapsedMs);
|
||||
}
|
||||
};
|
||||
|
||||
// --- ⬇️ 슬라이드 전환 효과 (수정) ⬇️ ---
|
||||
class SlideTransition : public TransitionStrategy {
|
||||
public:
|
||||
SlideTransition(long long duration, int surfaceWidth)
|
||||
: TransitionStrategy(duration), surfaceWidth_(surfaceWidth) {}
|
||||
void reset() override {}
|
||||
bool isComplete(long long elapsedMs) const override { return elapsedMs >= durationMs_; }
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer,
|
||||
MediaAsset& source, const AnimationState& sourceEnd,
|
||||
MediaAsset& dest, const AnimationState& destStart,
|
||||
long long elapsedMs) override {
|
||||
|
||||
float progress = std::clamp((float)elapsedMs / durationMs_, 0.0f, 1.0f);
|
||||
float easeProgress = progress * progress * (3.0f - 2.0f * progress);
|
||||
|
||||
float sourceSlideX = -surfaceWidth_ * easeProgress;
|
||||
float destSlideX = surfaceWidth_ * (1.0f - easeProgress);
|
||||
|
||||
// source는 마지막 위치(sourceEnd)에서 왼쪽으로 슬라이드 아웃
|
||||
renderer->drawMedia(buffer, source, 1.0f, sourceEnd.offsetX + sourceSlideX, sourceEnd.offsetY, sourceEnd.scale);
|
||||
// dest는 자신의 시작 위치(destStart) 오른쪽 밖에서 중앙으로 슬라이드 인
|
||||
renderer->drawMedia(buffer, dest, 1.0f, destStart.offsetX + destSlideX, destStart.offsetY, destStart.scale);
|
||||
|
||||
return isComplete(elapsedMs);
|
||||
}
|
||||
private:
|
||||
int surfaceWidth_;
|
||||
};
|
||||
|
||||
// ====================================================================
|
||||
// --- 모자이크 전환 효과 ---
|
||||
// ====================================================================
|
||||
class MosaicTransition : public TransitionStrategy {
|
||||
public:
|
||||
MosaicTransition(long long duration, int tilesX, int tilesY, std::mt19937& randomEngine)
|
||||
: TransitionStrategy(duration), tilesX_(tilesX), tilesY_(tilesY), randomEngine_(randomEngine) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() override {
|
||||
int totalTiles = tilesX_ * tilesY_;
|
||||
tileOrder_.resize(totalTiles);
|
||||
std::iota(tileOrder_.begin(), tileOrder_.end(), 0);
|
||||
std::shuffle(tileOrder_.begin(), tileOrder_.end(), randomEngine_);
|
||||
revealOrder_.resize(totalTiles);
|
||||
for(size_t i = 0; i < tileOrder_.size(); ++i) {
|
||||
revealOrder_[tileOrder_[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
bool isComplete(long long elapsedMs) const override {
|
||||
return elapsedMs >= durationMs_;
|
||||
}
|
||||
|
||||
bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer,
|
||||
MediaAsset& source, const AnimationState& sourceEnd,
|
||||
MediaAsset& dest, const AnimationState& destStart,
|
||||
long long elapsedMs) override {
|
||||
|
||||
float progress = std::clamp((float)elapsedMs / durationMs_, 0.0f, 1.0f);
|
||||
int totalTiles = tilesX_ * tilesY_;
|
||||
int tilesToReveal = static_cast<int>(progress * totalTiles);
|
||||
|
||||
const uint8_t* srcPixelData = source.getType() == MediaAsset::Type::IMAGE ? source.getImageData() : source.getRgbBuffer().data();
|
||||
const uint8_t* destPixelData = dest.getType() == MediaAsset::Type::IMAGE ? dest.getImageData() : dest.getRgbBuffer().data();
|
||||
if (!srcPixelData || !destPixelData) return isComplete(elapsedMs);
|
||||
|
||||
uint32_t* dstPixels = (uint32_t*)buffer.bits;
|
||||
int dstStride = buffer.stride;
|
||||
float tileWidth = (float)buffer.width / tilesX_;
|
||||
float tileHeight = (float)buffer.height / tilesY_;
|
||||
|
||||
for (int y = 0; y < buffer.height; ++y) {
|
||||
uint32_t* dstRow = dstPixels + y * dstStride;
|
||||
for (int x = 0; x < buffer.width; ++x) {
|
||||
int tileX = static_cast<int>(x / tileWidth);
|
||||
int tileY = static_cast<int>(y / tileHeight);
|
||||
int tileIndex = tileY * tilesX_ + tileX;
|
||||
int rank = revealOrder_[tileIndex];
|
||||
|
||||
const uint8_t* finalPixelData;
|
||||
if (rank < tilesToReveal) {
|
||||
// --- ⬇️ 수정된 부분: (x - offsetX) 공식 적용 ⬇️ ---
|
||||
int srcX = static_cast<int>((x - destStart.offsetX) / destStart.scale);
|
||||
int srcY = static_cast<int>((y - destStart.offsetY) / destStart.scale);
|
||||
if (srcX >= 0 && srcX < dest.getWidth() && srcY >= 0 && srcY < dest.getHeight()) {
|
||||
finalPixelData = &destPixelData[(srcY * dest.getWidth() + srcX) * 4];
|
||||
} else { continue; }
|
||||
} else {
|
||||
// --- ⬇️ 수정된 부분: (x - offsetX) 공식 적용 ⬇️ ---
|
||||
int srcX = static_cast<int>((x - sourceEnd.offsetX) / sourceEnd.scale);
|
||||
int srcY = static_cast<int>((y - sourceEnd.offsetY) / sourceEnd.scale);
|
||||
if (srcX >= 0 && srcX < source.getWidth() && srcY >= 0 && srcY < source.getHeight()) {
|
||||
finalPixelData = &srcPixelData[(srcY * source.getWidth() + srcX) * 4];
|
||||
} else { continue; }
|
||||
}
|
||||
dstRow[x] = (0xFF << 24) | (finalPixelData[0] << 16) | (finalPixelData[1] << 8) | finalPixelData[2];
|
||||
}
|
||||
}
|
||||
return isComplete(elapsedMs);
|
||||
}
|
||||
|
||||
private:
|
||||
int tilesX_, tilesY_;
|
||||
std::vector<int> tileOrder_;
|
||||
std::vector<int> revealOrder_;
|
||||
std::mt19937& randomEngine_;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <android/native_window.h>
|
||||
#include "MediaAsset.h"
|
||||
#include "AnimationStrategy.h" // AnimationState를 사용하기 위해 포함
|
||||
|
||||
class Renderer; // 전방 선언
|
||||
|
||||
/**
|
||||
* @brief 모든 전환 효과 전문가(Strategy) 클래스의 기반이 되는 인터페이스입니다.
|
||||
*/
|
||||
class TransitionStrategy {
|
||||
public:
|
||||
virtual ~TransitionStrategy() = default;
|
||||
|
||||
// --- ⬇️ 두 함수로 역할을 분리 ⬇️ ---
|
||||
/**
|
||||
* @brief 전환이 완료되었는지 확인합니다.
|
||||
* @param elapsedMs 전환 시작 후 경과 시간
|
||||
* @return 완료되었으면 true
|
||||
*/
|
||||
virtual bool isComplete(long long elapsedMs) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 전환 효과를 직접 렌더링 버퍼에 그립니다.
|
||||
* @param sourceEnd 사라지는 미디어의 최종 애니메이션 상태
|
||||
* @param destStart 나타나는 미디어의 시작 애니메이션 상태
|
||||
* @return 전환이 완료되었으면 true를 반환합니다.
|
||||
*/
|
||||
virtual bool execute(Renderer* renderer, ANativeWindow_Buffer& buffer,
|
||||
MediaAsset& source, const AnimationState& sourceEnd,
|
||||
MediaAsset& dest, const AnimationState& destStart,
|
||||
long long elapsedMs) = 0;
|
||||
|
||||
virtual void reset() = 0;
|
||||
|
||||
protected:
|
||||
TransitionStrategy(long long duration) : durationMs_(duration) {}
|
||||
long long durationMs_;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
#include <jni.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include "PlayerEngine.h"
|
||||
|
||||
extern JavaVM* g_vm;
|
||||
|
||||
template<typename T>
|
||||
T* toPlayerNative(jlong handle) { return reinterpret_cast<T*>(handle); }
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeGetDuration(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
return engine ? engine->getDuration() : 0.0;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeSeekTo(JNIEnv *env, jobject thiz, jlong handle, jdouble seconds) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->seekTo(seconds);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeInit(JNIEnv *env, jobject thiz) {
|
||||
PlayerEngine* engine = new PlayerEngine(g_vm, thiz);
|
||||
return reinterpret_cast<jlong>(engine);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeSeekBy(JNIEnv *env, jobject thiz, jlong handle, jdouble seconds) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->seekBy(seconds);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeSetSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->setSpeed(speed);
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeGetCurrentPosition(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
return engine ? engine->getCurrentPosition() : 0.0;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeGetSubtitleTracks(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
std::string tracks = engine ? engine->getSubtitleTracks() : "";
|
||||
return env->NewStringUTF(tracks.c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeSetSubtitleTrack(JNIEnv *env, jobject thiz, jlong handle, jint index) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->setSubtitleTrack(index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeSetDataSource(JNIEnv *env, jobject thiz, jlong handle, jint videoFd, jint jSubFd) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->setDataSource(videoFd, jSubFd);
|
||||
}
|
||||
|
||||
// 💡 추가된 비동기 준비
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativePrepareAsync(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->prepareAsync();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativePause(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->pause();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativePlay(JNIEnv *env, jobject thiz, jlong handle, jobject surface) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine && surface) {
|
||||
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
|
||||
ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBX_8888);
|
||||
engine->play(window);
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeStop(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) engine->stop();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_player_NativePlayer_nativeDestroy(JNIEnv *env, jobject thiz, jlong handle) {
|
||||
PlayerEngine* engine = toPlayerNative<PlayerEngine>(handle);
|
||||
if (engine) delete engine;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
#include <jni.h>
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <android/log.h>
|
||||
#include <thread>
|
||||
#include "Renderer.h"
|
||||
#include "Preloader.h"
|
||||
#include <android/bitmap.h>
|
||||
#define LOG_TAG "NativeRenderer"
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
|
||||
// --- ⬇️ 전역 렌더러, 프리로더 포인터 삭제! ⬇️ ---
|
||||
// Renderer* renderer = nullptr;
|
||||
// Preloader* preloader = nullptr;
|
||||
|
||||
// JavaVM과 콜백 관련 전역 변수는 앱 프로세스 전체에서 유일하므로 유지합니다.
|
||||
JavaVM* g_vm = nullptr;
|
||||
jobject g_callback_obj = nullptr;
|
||||
jmethodID g_callback_method_id = nullptr;
|
||||
|
||||
// JNI_OnLoad, callNextMediaCallback 함수는 기존과 동일
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
g_vm = vm;
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
void callNextMediaCallback() {
|
||||
JNIEnv* env;
|
||||
bool isAttached = false;
|
||||
// 현재 스레드가 JVM에 연결되어 있지 않다면 연결
|
||||
if (g_vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
if (g_vm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
|
||||
LOGE("Failed to attach current thread to JVM");
|
||||
return;
|
||||
}
|
||||
isAttached = true;
|
||||
}
|
||||
|
||||
if (g_callback_obj && g_callback_method_id) {
|
||||
env->CallVoidMethod(g_callback_obj, g_callback_method_id);
|
||||
}
|
||||
|
||||
// 이전에 연결되지 않았다면 연결 해제
|
||||
if (isAttached) {
|
||||
g_vm->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
// C++ 객체 포인터를 jlong으로, jlong을 C++ 객체 포인터로 안전하게 변환하는 헬퍼 함수
|
||||
template<typename T>
|
||||
T* toNative(jlong handle) {
|
||||
return reinterpret_cast<T*>(handle);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// [수정] jboolean -> jlong. Renderer 객체를 생성하고 그 주소(핸들)를 반환
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeInit(JNIEnv* env, jobject) {
|
||||
// Preloader는 Renderer가 내부적으로 소유하도록 변경하는 것이 더 좋습니다.
|
||||
// 여기서는 간단하게 Renderer만 생성하여 핸들링합니다.
|
||||
Renderer* renderer = new Renderer();
|
||||
LOGI("Native renderer instance created at address: %p", renderer);
|
||||
return reinterpret_cast<jlong>(renderer);
|
||||
}
|
||||
|
||||
// [수정] 핸들을 파라미터로 받아 해당 객체를 파괴
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeDestroy(JNIEnv* env, jobject, jlong nativeHandle) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
LOGI("Destroying native renderer instance at address: %p", renderer);
|
||||
delete renderer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStopRenderLoop(JNIEnv* env, jobject, jlong nativeHandle) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->stopRenderLoop();
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartRenderLoop(JNIEnv* env, jobject, jlong nativeHandle, jobject surface) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (!renderer || !surface) return;
|
||||
|
||||
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
|
||||
if (!window) {
|
||||
LOGE("Could not get ANativeWindow from Surface.");
|
||||
return;
|
||||
}
|
||||
ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBX_8888);
|
||||
renderer->startRenderLoop(window);
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
|
||||
|
||||
// [수정] 모든 함수가 nativeHandle을 첫 파라미터로 받도록 변경
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeRender(JNIEnv* env, jobject, jlong nativeHandle, jobject surface) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (!renderer || !surface) return;
|
||||
|
||||
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
|
||||
if (!window) {
|
||||
LOGE("Could not get ANativeWindow from Surface.");
|
||||
return;
|
||||
}
|
||||
renderer->renderFrame(window);
|
||||
ANativeWindow_release(window);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeForceNext(JNIEnv* env, jobject, jlong nativeHandle) {
|
||||
Renderer* renderer = reinterpret_cast<Renderer*>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->forceNext(); // Renderer에 추가할 함수 호출
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetWeatherBitmap(JNIEnv* env, jobject, jlong nativeHandle, jobject bitmap) {
|
||||
Renderer* renderer = reinterpret_cast<Renderer*>(nativeHandle);
|
||||
if (!renderer) return;
|
||||
|
||||
// 비트맵이 null로 넘어오면 데이터를 지움
|
||||
if (bitmap == nullptr) {
|
||||
renderer->clearWeatherBitmap();
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidBitmapInfo info;
|
||||
void* pixels;
|
||||
if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) return;
|
||||
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) return;
|
||||
|
||||
renderer->updateWeatherBitmap(pixels, info.width, info.height);
|
||||
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeStartNextPreload(JNIEnv* env, jobject, jlong nativeHandle, jint fd) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
// Preloader가 Renderer의 일부가 되었다고 가정하고 호출 (추후 Renderer 수정 필요)
|
||||
// 여기서는 간단하게 setNextMedia를 호출하는 것으로 변경합니다.
|
||||
renderer->setNextMedia(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetImageRenderFrame(JNIEnv* env, jobject, jlong nativeHandle, jint frame) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
// Preloader가 Renderer의 일부가 되었다고 가정하고 호출 (추후 Renderer 수정 필요)
|
||||
// 여기서는 간단하게 setNextMedia를 호출하는 것으로 변경합니다.
|
||||
renderer->setImageRenderFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetAnimationSpeed(JNIEnv* env, jobject, jlong nativeHandle, jfloat speed) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->setAnimationSpeed(speed);
|
||||
}
|
||||
}
|
||||
|
||||
// --- ⬇️ 새로 추가할 JNI 함수들 ⬇️ ---
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetAnimationMode(JNIEnv* env, jobject, jlong nativeHandle, jint mode) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->setAnimationMode(mode);
|
||||
}
|
||||
}
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetTransitionMode(JNIEnv* env, jobject, jlong nativeHandle, jint mode) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->setTransitionMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetFadeDuration(JNIEnv* env, jobject, jlong nativeHandle, jint duration) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->setFadeDuration(duration);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetPageTurnDelay(JNIEnv* env, jobject, jlong nativeHandle, jint duration) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
renderer->setPageTurnDelay(duration);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeGetDebugInfo(JNIEnv* env, jobject, jlong nativeHandle) {
|
||||
Renderer* renderer = toNative<Renderer>(nativeHandle);
|
||||
if (renderer) {
|
||||
std::string debugInfo = renderer->getDebugInfo();
|
||||
return env->NewStringUTF(debugInfo.c_str());
|
||||
}
|
||||
return env->NewStringUTF("Renderer handle is invalid or null.");
|
||||
}
|
||||
|
||||
|
||||
// --- 참고: nativeSetNextMediaCallback은 전역이라 일단 그대로 둡니다 ---
|
||||
JNIEXPORT void JNICALL
|
||||
Java_bums_lunatic_launcher_wall_NativeRenderer_nativeSetNextMediaCallback(JNIEnv* env, jobject, jobject callback) {
|
||||
if (g_callback_obj) {
|
||||
env->DeleteGlobalRef(g_callback_obj);
|
||||
}
|
||||
g_callback_obj = env->NewGlobalRef(callback);
|
||||
jclass clazz = env->GetObjectClass(callback);
|
||||
g_callback_method_id = env->GetMethodID(clazz, "onNextMediaRequested", "()V");
|
||||
|
||||
if (!g_callback_method_id) {
|
||||
LOGE("Could not find onNextMediaRequested method ID.");
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// Created by JIBUM HAN on 2026. 4. 11..
|
||||
//
|
||||
#ifndef SONIC_H_
|
||||
#define SONIC_H_
|
||||
|
||||
/* Sonic library
|
||||
Copyright 2010
|
||||
Bill Cox
|
||||
This file is part of the Sonic Library.
|
||||
|
||||
This file is licensed under the Apache 2.0 license.
|
||||
*/
|
||||
|
||||
/*
|
||||
The Sonic Library implements a new algorithm invented by Bill Cox for the
|
||||
specific purpose of speeding up speech by high factors at high quality. It
|
||||
generates smooth speech at speed up factors as high as 6X, possibly more. It is
|
||||
also capable of slowing down speech, and generates high quality results
|
||||
regardless of the speed up or slow down factor. For speeding up speech by 2X or
|
||||
more, the following equation is used:
|
||||
|
||||
newSamples = period/(speed - 1.0)
|
||||
scale = 1.0/newSamples;
|
||||
|
||||
where period is the current pitch period, determined using AMDF or any other
|
||||
pitch estimator, and speed is the speedup factor. If the current position in
|
||||
the input stream is pointed to by "samples", and the current output stream
|
||||
position is pointed to by "out", then newSamples number of samples can be
|
||||
generated with:
|
||||
|
||||
out[t] = (samples[t]*(newSamples - t) + samples[t + period]*t)/newSamples;
|
||||
|
||||
where t = 0 to newSamples - 1.
|
||||
|
||||
For speed factors < 2X, the PICOLA algorithm is used. The above
|
||||
algorithm is first used to double the speed of one pitch period. Then, enough
|
||||
input is directly copied from the input to the output to achieve the desired
|
||||
speed up factor, where 1.0 < speed < 2.0. The amount of data copied is derived:
|
||||
|
||||
speed = (2*period + length)/(period + length)
|
||||
speed*length + speed*period = 2*period + length
|
||||
length(speed - 1) = 2*period - speed*period
|
||||
length = period*(2 - speed)/(speed - 1)
|
||||
|
||||
For slowing down speech where 0.5 < speed < 1.0, a pitch period is inserted into
|
||||
the output twice, and length of input is copied from the input to the output
|
||||
until the output desired speed is reached. The length of data copied is:
|
||||
|
||||
length = period*(speed - 0.5)/(1 - speed)
|
||||
|
||||
For slow down factors below 0.5, no data is copied, and an algorithm
|
||||
similar to high speed factors is used.
|
||||
*/
|
||||
|
||||
/* Uncomment this to use sin-wav based overlap add which in theory can improve
|
||||
sound quality slightly, at the expense of lots of floating point math. */
|
||||
/* #define SONIC_USE_SIN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef SONIC_INTERNAL
|
||||
/* The following #define's are used to change the names of the routines defined
|
||||
* here so that a new library (i.e. speedy) can reuse these names, and then call
|
||||
* the original names. We do this for two reasons: 1) we don't want to change
|
||||
* the original API, and 2) we want to add a shim, using the original names and
|
||||
* still call these routines.
|
||||
*
|
||||
* Original users of this API and the libsonic library need to do nothing. The
|
||||
* original behavior remains.
|
||||
*
|
||||
* A new user that add some additional functionality above this library (a shim)
|
||||
* should #define SONIC_INTERNAL before including this file, undefine all these
|
||||
* symbols and call the sonicIntXXX functions directly.
|
||||
*/
|
||||
#define sonicCreateStream sonicIntCreateStream
|
||||
#define sonicDestroyStream sonicIntDestroyStream
|
||||
#define sonicWriteFloatToStream sonicIntWriteFloatToStream
|
||||
#define sonicWriteShortToStream sonicIntWriteShortToStream
|
||||
#define sonicWriteUnsignedCharToStream sonicIntWriteUnsignedCharToStream
|
||||
#define sonicReadFloatFromStream sonicIntReadFloatFromStream
|
||||
#define sonicReadShortFromStream sonicIntReadShortFromStream
|
||||
#define sonicReadUnsignedCharFromStream sonicIntReadUnsignedCharFromStream
|
||||
#define sonicFlushStream sonicIntFlushStream
|
||||
#define sonicSamplesAvailable sonicIntSamplesAvailable
|
||||
#define sonicGetSpeed sonicIntGetSpeed
|
||||
#define sonicSetSpeed sonicIntSetSpeed
|
||||
#define sonicGetPitch sonicIntGetPitch
|
||||
#define sonicSetPitch sonicIntSetPitch
|
||||
#define sonicGetRate sonicIntGetRate
|
||||
#define sonicSetRate sonicIntSetRate
|
||||
#define sonicGetVolume sonicIntGetVolume
|
||||
#define sonicSetVolume sonicIntSetVolume
|
||||
#define sonicGetQuality sonicIntGetQuality
|
||||
#define sonicSetQuality sonicIntSetQuality
|
||||
#define sonicGetSampleRate sonicIntGetSampleRate
|
||||
#define sonicSetSampleRate sonicIntSetSampleRate
|
||||
#define sonicGetNumChannels sonicIntGetNumChannels
|
||||
#define sonicGetUserData sonicIntGetUserData
|
||||
#define sonicSetUserData sonicIntSetUserData
|
||||
#define sonicSetNumChannels sonicIntSetNumChannels
|
||||
#define sonicChangeFloatSpeed sonicIntChangeFloatSpeed
|
||||
#define sonicChangeShortSpeed sonicIntChangeShortSpeed
|
||||
#define sonicEnableNonlinearSpeedup sonicIntEnableNonlinearSpeedup
|
||||
#define sonicSetDurationFeedbackStrength sonicIntSetDurationFeedbackStrength
|
||||
#define sonicComputeSpectrogram sonicIntComputeSpectrogram
|
||||
#define sonicGetSpectrogram sonicIntGetSpectrogram
|
||||
|
||||
#endif /* SONIC_INTERNAL */
|
||||
|
||||
/* This specifies the range of voice pitches we try to match.
|
||||
Note that if we go lower than 65, we could overflow in findPitchInRange */
|
||||
#ifndef SONIC_MIN_PITCH
|
||||
#define SONIC_MIN_PITCH 65
|
||||
#endif /* SONIC_MIN_PITCH */
|
||||
#ifndef SONIC_MAX_PITCH
|
||||
#define SONIC_MAX_PITCH 400
|
||||
#endif /* SONIC_MAX_PITCH */
|
||||
|
||||
/* The following values are used to clamp inputs such as speed to sane values.
|
||||
*/
|
||||
#define SONIC_MIN_VOLUME 0.01f
|
||||
#define SONIC_MAX_VOLUME 100.0f
|
||||
#define SONIC_MIN_SPEED 0.05f
|
||||
#define SONIC_MAX_SPEED 20.0f
|
||||
#define SONIC_MIN_PITCH_SETTING 0.05f
|
||||
#define SONIC_MAX_PITCH_SETTING 20.0f
|
||||
#define SONIC_MIN_RATE 0.05f
|
||||
#define SONIC_MAX_RATE 20.0f
|
||||
#define SONIC_MIN_SAMPLE_RATE 1000
|
||||
#define SONIC_MAX_SAMPLE_RATE 500000
|
||||
#define SONIC_MIN_CHANNELS 1
|
||||
#define SONIC_MAX_CHANNELS 32
|
||||
|
||||
/* These are used to down-sample some inputs to improve speed */
|
||||
#define SONIC_AMDF_FREQ 4000
|
||||
|
||||
struct sonicStreamStruct;
|
||||
typedef struct sonicStreamStruct* sonicStream;
|
||||
|
||||
/* For all of the following functions, numChannels is multiplied by numSamples
|
||||
to determine the actual number of values read or returned. */
|
||||
|
||||
/* Create a sonic stream. Return NULL only if we are out of memory and cannot
|
||||
allocate the stream. Set numChannels to 1 for mono, and 2 for stereo. */
|
||||
sonicStream sonicCreateStream(int sampleRate, int numChannels);
|
||||
/* Destroy the sonic stream. */
|
||||
void sonicDestroyStream(sonicStream stream);
|
||||
/* Attach user data to the stream. */
|
||||
void sonicSetUserData(sonicStream stream, void *userData);
|
||||
/* Retrieve user data attached to the stream. */
|
||||
void *sonicGetUserData(sonicStream stream);
|
||||
/* Use this to write floating point data to be speed up or down into the stream.
|
||||
Values must be between -1 and 1. Return 0 if memory realloc failed,
|
||||
otherwise 1 */
|
||||
int sonicWriteFloatToStream(sonicStream stream, const float* samples, int numSamples);
|
||||
/* Use this to write 16-bit data to be speed up or down into the stream.
|
||||
Return 0 if memory realloc failed, otherwise 1 */
|
||||
int sonicWriteShortToStream(sonicStream stream, const short* samples, int numSamples);
|
||||
/* Use this to write 8-bit unsigned data to be speed up or down into the stream.
|
||||
Return 0 if memory realloc failed, otherwise 1 */
|
||||
int sonicWriteUnsignedCharToStream(sonicStream stream, const unsigned char* samples,
|
||||
int numSamples);
|
||||
/* Use this to read floating point data out of the stream. Sometimes no data
|
||||
will be available, and zero is returned, which is not an error condition. */
|
||||
int sonicReadFloatFromStream(sonicStream stream, float* samples,
|
||||
int maxSamples);
|
||||
/* Use this to read 16-bit data out of the stream. Sometimes no data will
|
||||
be available, and zero is returned, which is not an error condition. */
|
||||
int sonicReadShortFromStream(sonicStream stream, short* samples,
|
||||
int maxSamples);
|
||||
/* Use this to read 8-bit unsigned data out of the stream. Sometimes no data
|
||||
will be available, and zero is returned, which is not an error condition. */
|
||||
int sonicReadUnsignedCharFromStream(sonicStream stream, unsigned char* samples,
|
||||
int maxSamples);
|
||||
/* Force the sonic stream to generate output using whatever data it currently
|
||||
has. No extra delay will be added to the output, but flushing in the middle
|
||||
of words could introduce distortion. */
|
||||
int sonicFlushStream(sonicStream stream);
|
||||
/* Return the number of samples in the output buffer */
|
||||
int sonicSamplesAvailable(sonicStream stream);
|
||||
/* Get the speed of the stream. */
|
||||
float sonicGetSpeed(sonicStream stream);
|
||||
/* Set the speed of the stream. */
|
||||
void sonicSetSpeed(sonicStream stream, float speed);
|
||||
/* Get the pitch of the stream. */
|
||||
float sonicGetPitch(sonicStream stream);
|
||||
/* Set the pitch of the stream. */
|
||||
void sonicSetPitch(sonicStream stream, float pitch);
|
||||
/* Get the rate of the stream. */
|
||||
float sonicGetRate(sonicStream stream);
|
||||
/* Set the rate of the stream. */
|
||||
void sonicSetRate(sonicStream stream, float rate);
|
||||
/* Get the scaling factor of the stream. */
|
||||
float sonicGetVolume(sonicStream stream);
|
||||
/* Set the scaling factor of the stream. */
|
||||
void sonicSetVolume(sonicStream stream, float volume);
|
||||
/* Chord pitch is DEPRECATED. AFAIK, it was never used by anyone. These
|
||||
functions still exist to avoid breaking existing code. */
|
||||
/* Get the chord pitch setting. */
|
||||
int sonicGetChordPitch(sonicStream stream);
|
||||
/* Set chord pitch mode on or off. Default is off. See the documentation
|
||||
page for a description of this feature. */
|
||||
void sonicSetChordPitch(sonicStream stream, int useChordPitch);
|
||||
/* Get the quality setting. */
|
||||
int sonicGetQuality(sonicStream stream);
|
||||
/* Set the "quality". Default 0 is virtually as good as 1, but very much
|
||||
* faster. */
|
||||
void sonicSetQuality(sonicStream stream, int quality);
|
||||
/* Get the sample rate of the stream. */
|
||||
int sonicGetSampleRate(sonicStream stream);
|
||||
/* Set the sample rate of the stream. This will drop any samples that have not
|
||||
* been read. */
|
||||
void sonicSetSampleRate(sonicStream stream, int sampleRate);
|
||||
/* Get the number of channels. */
|
||||
int sonicGetNumChannels(sonicStream stream);
|
||||
/* Set the number of channels. This will drop any samples that have not been
|
||||
* read. */
|
||||
void sonicSetNumChannels(sonicStream stream, int numChannels);
|
||||
/* This is a non-stream oriented interface to just change the speed of a sound
|
||||
sample. It works in-place on the sample array, so there must be at least
|
||||
speed*numSamples available space in the array. Returns the new number of
|
||||
samples. */
|
||||
int sonicChangeFloatSpeed(float* samples, int numSamples, float speed,
|
||||
float pitch, float rate, float volume,
|
||||
int useChordPitch, int sampleRate, int numChannels);
|
||||
/* This is a non-stream oriented interface to just change the speed of a sound
|
||||
sample. It works in-place on the sample array, so there must be at least
|
||||
speed*numSamples available space in the array. Returns the new number of
|
||||
samples. */
|
||||
int sonicChangeShortSpeed(short* samples, int numSamples, float speed,
|
||||
float pitch, float rate, float volume,
|
||||
int useChordPitch, int sampleRate, int numChannels);
|
||||
|
||||
#ifdef SONIC_SPECTROGRAM
|
||||
/*
|
||||
This code generates high quality spectrograms from sound samples, using
|
||||
Time-Aliased-FFTs as described at:
|
||||
|
||||
https://github.com/waywardgeek/spectrogram
|
||||
|
||||
Basically, two adjacent pitch periods are overlap-added to create a sound
|
||||
sample that accurately represents the speech sound at that moment in time.
|
||||
This set of samples is converted to a spetral line using an FFT, and the result
|
||||
is saved as a single spectral line at that moment in time. The resulting
|
||||
spectral lines vary in resolution (it is equal to the number of samples in the
|
||||
pitch period), and the spacing of spectral lines also varies (proportional to
|
||||
the numver of samples in the pitch period).
|
||||
|
||||
To generate a bitmap, linear interpolation is used to render the grayscale
|
||||
value at any particular point in time and frequency.
|
||||
*/
|
||||
|
||||
#define SONIC_MAX_SPECTRUM_FREQ 5000
|
||||
|
||||
struct sonicSpectrogramStruct;
|
||||
struct sonicBitmapStruct;
|
||||
typedef struct sonicSpectrogramStruct* sonicSpectrogram;
|
||||
typedef struct sonicBitmapStruct* sonicBitmap;
|
||||
|
||||
/* sonicBitmap objects represent spectrograms as grayscale bitmaps where each
|
||||
pixel is from 0 (black) to 255 (white). Bitmaps are rows*cols in size.
|
||||
Rows are indexed top to bottom and columns are indexed left to right */
|
||||
struct sonicBitmapStruct {
|
||||
unsigned char* data;
|
||||
int numRows;
|
||||
int numCols;
|
||||
};
|
||||
|
||||
/* Enable coomputation of a spectrogram on the fly. */
|
||||
void sonicComputeSpectrogram(sonicStream stream);
|
||||
|
||||
/* Get the spectrogram. */
|
||||
sonicSpectrogram sonicGetSpectrogram(sonicStream stream);
|
||||
|
||||
/* Create an empty spectrogram. Called automatically if sonicComputeSpectrogram
|
||||
has been called. */
|
||||
sonicSpectrogram sonicCreateSpectrogram(int sampleRate);
|
||||
|
||||
/* Destroy the spectrotram. This is called automatically when calling
|
||||
sonicDestroyStream. */
|
||||
void sonicDestroySpectrogram(sonicSpectrogram spectrogram);
|
||||
|
||||
/* Convert the spectrogram to a bitmap. Caller must destroy bitmap when done. */
|
||||
sonicBitmap sonicConvertSpectrogramToBitmap(sonicSpectrogram spectrogram,
|
||||
int numRows, int numCols);
|
||||
|
||||
/* Destroy a bitmap returned by sonicConvertSpectrogramToBitmap. */
|
||||
void sonicDestroyBitmap(sonicBitmap bitmap);
|
||||
|
||||
int sonicWritePGM(sonicBitmap bitmap, char* fileName);
|
||||
|
||||
/* Add two pitch periods worth of samples to the spectrogram. There must be
|
||||
2*period samples. Time should advance one pitch period for each call to
|
||||
this function. */
|
||||
void sonicAddPitchPeriodToSpectrogram(sonicSpectrogram spectrogram,
|
||||
short* samples, int numSamples,
|
||||
int numChannels);
|
||||
#endif /* SONIC_SPECTROGRAM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SONIC_H_ */
|
||||
@@ -1,168 +1,168 @@
|
||||
//package android.print;
|
||||
//
|
||||
//import android.app.Activity;
|
||||
//import android.content.Context;
|
||||
//import android.os.Bundle;
|
||||
//import android.os.CancellationSignal;
|
||||
//import android.os.ParcelFileDescriptor;
|
||||
//import android.webkit.WebView;
|
||||
//import android.webkit.WebViewClient;
|
||||
//
|
||||
//import java.io.File;
|
||||
//import java.io.FileInputStream;
|
||||
//import java.io.FileOutputStream;
|
||||
//import java.io.IOException;
|
||||
//import java.io.InputStream;
|
||||
//import java.io.OutputStream;
|
||||
//
|
||||
//public class PDFPrint {
|
||||
//
|
||||
// public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
||||
// final WebView mWebView = new WebView(context);
|
||||
// mWebView.setWebViewClient(new WebViewClient() {
|
||||
// @Override
|
||||
// public void onPageFinished(WebView view, String url) {
|
||||
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||
// .build();
|
||||
//
|
||||
// final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
||||
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||
// @Override
|
||||
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteCancelled() {
|
||||
// super.onWriteCancelled();
|
||||
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteFailed(CharSequence error) {
|
||||
// super.onWriteFailed(error);
|
||||
// onPDFPrintListener.onError(new Exception(error.toString()));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteFinished(PageRange[] pages) {
|
||||
// super.onWriteFinished(pages);
|
||||
// onPDFPrintListener.onSuccess(file);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }, null);
|
||||
// }
|
||||
// });
|
||||
// mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
||||
// }
|
||||
//
|
||||
// public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
||||
// PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||
// .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||
// .setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||
// .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||
// .build();
|
||||
//
|
||||
// final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
||||
// documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||
// @Override
|
||||
// public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||
// documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteCancelled() {
|
||||
// super.onWriteCancelled();
|
||||
// onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteFailed(CharSequence error) {
|
||||
// super.onWriteFailed(error);
|
||||
// try {
|
||||
// if (error != null && error.toString().length() > 0) {
|
||||
// onPDFPrintListener.onError(new Exception(error.toString()));
|
||||
// } else {
|
||||
// onPDFPrintListener.onError(new Exception("Empty Page"));
|
||||
// }
|
||||
// }catch (Exception e) {e.printStackTrace();}
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onWriteFinished(PageRange[] pages) {
|
||||
// super.onWriteFinished(pages);
|
||||
// onPDFPrintListener.onSuccess(file);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }, null);
|
||||
// }
|
||||
//
|
||||
// private static ParcelFileDescriptor getOutputFile(File file) {
|
||||
// try {
|
||||
// if (!file.exists()) {
|
||||
// file.createNewFile();
|
||||
// }
|
||||
// return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
||||
// PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
||||
// String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
||||
// return printManager.print(jobName, new PrintDocumentAdapter() {
|
||||
// @Override
|
||||
// public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||
// InputStream input = null;
|
||||
// OutputStream output = null;
|
||||
//
|
||||
// try {
|
||||
//
|
||||
// input = new FileInputStream(pdfFileToPrint);
|
||||
// output = new FileOutputStream(destination.getFileDescriptor());
|
||||
//
|
||||
// byte[] buf = new byte[1024];
|
||||
// int bytesRead;
|
||||
//
|
||||
// while ((bytesRead = input.read(buf)) > 0) {
|
||||
// output.write(buf, 0, bytesRead);
|
||||
// }
|
||||
//
|
||||
// callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// } finally {
|
||||
// try {
|
||||
// input.close();
|
||||
// output.close();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
||||
// if (cancellationSignal.isCanceled()) {
|
||||
// callback.onLayoutCancelled();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
||||
// callback.onLayoutFinished(pdi, true);
|
||||
// }
|
||||
// }, printAttributes);
|
||||
// }
|
||||
//
|
||||
// public interface OnPDFPrintListener {
|
||||
// void onSuccess(File file);
|
||||
//
|
||||
// void onError(Exception exception);
|
||||
// }
|
||||
//}
|
||||
package android.print;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class PDFPrint {
|
||||
|
||||
public static void generatePDFFromHTML(final Context context, final File file, final String htmlString, final OnPDFPrintListener onPDFPrintListener) {
|
||||
final WebView mWebView = new WebView(context);
|
||||
mWebView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||
.build();
|
||||
|
||||
final PrintDocumentAdapter documentAdapter = mWebView.createPrintDocumentAdapter(file.getName());
|
||||
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||
@Override
|
||||
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||
|
||||
@Override
|
||||
public void onWriteCancelled() {
|
||||
super.onWriteCancelled();
|
||||
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWriteFailed(CharSequence error) {
|
||||
super.onWriteFailed(error);
|
||||
onPDFPrintListener.onError(new Exception(error.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWriteFinished(PageRange[] pages) {
|
||||
super.onWriteFinished(pages);
|
||||
onPDFPrintListener.onSuccess(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
mWebView.loadData(htmlString.replaceAll("#", "%23"), "text/HTML", "UTF-8");
|
||||
}
|
||||
|
||||
public static void generatePDFFromWebView(final File file, final WebView webView, final OnPDFPrintListener onPDFPrintListener) {
|
||||
PrintAttributes printAttributes = new PrintAttributes.Builder()
|
||||
.setMediaSize(PrintAttributes.MediaSize.ISO_A4)
|
||||
.setResolution(new PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
|
||||
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
|
||||
.build();
|
||||
|
||||
final PrintDocumentAdapter documentAdapter = webView.createPrintDocumentAdapter(file.getName());
|
||||
documentAdapter.onLayout(null, printAttributes, null, new PrintDocumentAdapter.LayoutResultCallback() {
|
||||
@Override
|
||||
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
|
||||
documentAdapter.onWrite(new PageRange[]{PageRange.ALL_PAGES}, getOutputFile(file), null, new PrintDocumentAdapter.WriteResultCallback() {
|
||||
|
||||
@Override
|
||||
public void onWriteCancelled() {
|
||||
super.onWriteCancelled();
|
||||
onPDFPrintListener.onError(new Exception("PDF Write cancelled."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWriteFailed(CharSequence error) {
|
||||
super.onWriteFailed(error);
|
||||
try {
|
||||
if (error != null && error.toString().length() > 0) {
|
||||
onPDFPrintListener.onError(new Exception(error.toString()));
|
||||
} else {
|
||||
onPDFPrintListener.onError(new Exception("Empty Page"));
|
||||
}
|
||||
}catch (Exception e) {e.printStackTrace();}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWriteFinished(PageRange[] pages) {
|
||||
super.onWriteFinished(pages);
|
||||
onPDFPrintListener.onSuccess(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
private static ParcelFileDescriptor getOutputFile(File file) {
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PrintJob printPDF(final Activity activity, final File pdfFileToPrint, final PrintAttributes printAttributes) {
|
||||
PrintManager printManager = (PrintManager) activity.getSystemService(Context.PRINT_SERVICE);
|
||||
String jobName = Long.valueOf(System.currentTimeMillis()).toString();
|
||||
return printManager.print(jobName, new PrintDocumentAdapter() {
|
||||
@Override
|
||||
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
|
||||
try {
|
||||
|
||||
input = new FileInputStream(pdfFileToPrint);
|
||||
output = new FileOutputStream(destination.getFileDescriptor());
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = input.read(buf)) > 0) {
|
||||
output.write(buf, 0, bytesRead);
|
||||
}
|
||||
|
||||
callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
input.close();
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
|
||||
if (cancellationSignal.isCanceled()) {
|
||||
callback.onLayoutCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(pdfFileToPrint.getName()).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
|
||||
callback.onLayoutFinished(pdi, true);
|
||||
}
|
||||
}, printAttributes);
|
||||
}
|
||||
|
||||
public interface OnPDFPrintListener {
|
||||
void onSuccess(File file);
|
||||
|
||||
void onError(Exception exception);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
#!/bin/bash
|
||||
|
||||
### Describe Your Target Android Api or Architectures ###
|
||||
ANDROID_API_LEVEL="25"
|
||||
ARCH_LIST=("armv8a" "armv7a" "x86" "x86-64")
|
||||
|
||||
|
||||
### Supported Architectures "armv8a" "armv7a" "x86" "x86-64" #######
|
||||
|
||||
### Enable FFMPEG BUILD MODULES ####
|
||||
ENABLED_CONFIG="\
|
||||
--enable-avcodec \
|
||||
--enable-avformat \
|
||||
--enable-avutil \
|
||||
--enable-swscale \
|
||||
--enable-libdav1d \
|
||||
--enable-demuxer=* \
|
||||
--enable-decoder=h264,hevc,vp8,vp9,libdav1d,flv,vp6f,adpcm_swf,mpeg4,wmv3,mpeg2video,mpeg2audio,msmpeg4v2,msmpeg4v3,theora,amrnb,amrwb,dvvideo,h263,mjpeg,png,jpeg,bmp,webp,mp3,aac,ac3,eac3,flac,opus,vorbis,pcm_s16le,pcm_s24le,alac,wma,ass,ssa,mov_text,subrip,webvtt,dvbsub,dvdsub \
|
||||
--enable-parser=* \
|
||||
--enable-bsf=* \
|
||||
--enable-shared "
|
||||
|
||||
|
||||
### Disable FFMPEG BUILD MODULES ####
|
||||
DISABLED_CONFIG="\
|
||||
--disable-small \
|
||||
--disable-zlib \
|
||||
--disable-swresample \
|
||||
--disable-avfilter \
|
||||
--disable-v4l2-m2m \
|
||||
--disable-cuda-llvm \
|
||||
--disable-indevs \
|
||||
--disable-libxml2 \
|
||||
--disable-avdevice \
|
||||
--disable-network \
|
||||
--disable-static \
|
||||
--disable-debug \
|
||||
--disable-ffplay \
|
||||
--disable-ffprobe \
|
||||
--disable-doc \
|
||||
--disable-symver \
|
||||
--disable-gpl "
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
############ Dont Change ################
|
||||
############ Dont Change ################
|
||||
############ Dont Change ################
|
||||
############ Dont Change ################
|
||||
############ Dont Change ################
|
||||
|
||||
SYSROOT="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
|
||||
LLVM_AR="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar"
|
||||
LLVM_NM="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-nm"
|
||||
LLVM_RANLIB="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib"
|
||||
LLVM_STRIP="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip"
|
||||
export ASFLAGS="-fPIC"
|
||||
|
||||
|
||||
buildLibdav1d(){
|
||||
TARGET_ARCH=$1
|
||||
TARGET_CPU=$2
|
||||
PREFIX=$3
|
||||
CROSS_PREFIX=$4
|
||||
EXTRA_CFLAGS=$5
|
||||
EXTRA_CXXFLAGS=$6
|
||||
EXTRA_CONFIG=$7
|
||||
CLANG="${CROSS_PREFIX}clang"
|
||||
CLANGXX="${CROSS_PREFIX}clang++"
|
||||
|
||||
if [ "$TARGET_ARCH" = "i686" ]; then
|
||||
TARGET_ARCH="x86"
|
||||
fi
|
||||
|
||||
if [ ! -d "dav1d" ]; then
|
||||
echo "Cloning libdav1d..."
|
||||
git clone https://code.videolan.org/videolan/dav1d.git
|
||||
else
|
||||
echo "Updating libdav1d..."
|
||||
cd dav1d
|
||||
git pull
|
||||
cd ..
|
||||
fi
|
||||
|
||||
cd dav1d
|
||||
# --- Create cross file ---
|
||||
CROSS_FILE="android-$TARGET_ARCH-$ANDROID_API_LEVEL-cross.messon"
|
||||
cat > "$CROSS_FILE" <<EOF
|
||||
[binaries]
|
||||
c = '$CLANG'
|
||||
cpp = '$CLANGXX'
|
||||
ar = '$LLVM_AR'
|
||||
strip = '$LLVM_STRIP'
|
||||
pkg-config = 'pkg-config'
|
||||
|
||||
[properties]
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[built-in options]
|
||||
c_args = ['-fpic']
|
||||
cpp_args = ['-fpic']
|
||||
c_link_args = ['-Wl,-z,max-page-size=16384']
|
||||
|
||||
[host_machine]
|
||||
system = 'android'
|
||||
cpu_family = '$TARGET_ARCH'
|
||||
cpu = '$TARGET_CPU'
|
||||
endian = 'little'
|
||||
EOF
|
||||
|
||||
echo "Meson cross file created: $CROSS_FILE"
|
||||
rm -rf build
|
||||
meson setup build \
|
||||
--default-library=static \
|
||||
--prefix=$PREFIX \
|
||||
--buildtype release \
|
||||
--cross-file=$CROSS_FILE
|
||||
|
||||
ninja -C build
|
||||
ninja -C build install
|
||||
}
|
||||
|
||||
|
||||
|
||||
configure_ffmpeg(){
|
||||
TARGET_ARCH=$1
|
||||
TARGET_CPU=$2
|
||||
PREFIX=$3
|
||||
CROSS_PREFIX=$4
|
||||
EXTRA_CFLAGS=$5
|
||||
EXTRA_CXXFLAGS=$6
|
||||
EXTRA_CONFIG=$7
|
||||
|
||||
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig"
|
||||
CLANG="${CROSS_PREFIX}clang"
|
||||
CLANGXX="${CROSS_PREFIX}clang++"
|
||||
|
||||
cd "$FFMPEG_SOURCE_DIR"
|
||||
./configure \
|
||||
--disable-everything \
|
||||
--target-os=android \
|
||||
--arch=$TARGET_ARCH \
|
||||
--cpu=$TARGET_CPU \
|
||||
--pkg-config=pkg-config \
|
||||
--enable-cross-compile \
|
||||
--cross-prefix="$CROSS_PREFIX" \
|
||||
--cc="$CLANG" \
|
||||
--cxx="$CLANGXX" \
|
||||
--sysroot="$SYSROOT" \
|
||||
--prefix="$PREFIX" \
|
||||
--extra-cflags="-fpic -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D__BIONIC_NO_PAGE_SIZE_MACRO -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security $EXTRA_CFLAGS -I$PREFIX/include " \
|
||||
--extra-cxxflags="-fpic -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D__BIONIC_NO_PAGE_SIZE_MACRO -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -std=c++17 -fexceptions -frtti $EXTRA_CXXFLAGS -I$PREFIX/include " \
|
||||
--extra-ldflags=" -Wl,-z,max-page-size=16384 -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--no-undefined-version -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -L$SYSROOT/usr/lib/$TARGET_ARCH-linux-android/$ANDROID_API_LEVEL -L$PREFIX/lib" \
|
||||
--enable-pic \
|
||||
${ENABLED_CONFIG} \
|
||||
${DISABLED_CONFIG} \
|
||||
--ar="$LLVM_AR" \
|
||||
--nm="$LLVM_NM" \
|
||||
--ranlib="$LLVM_RANLIB" \
|
||||
--strip="$LLVM_STRIP" \
|
||||
${EXTRA_CONFIG}
|
||||
|
||||
make clean
|
||||
make -j2
|
||||
make install -j2
|
||||
|
||||
}
|
||||
|
||||
echo -e "\e[1;32mCompiling FFMPEG for Android...\e[0m"
|
||||
|
||||
for ARCH in "${ARCH_LIST[@]}"; do
|
||||
case "$ARCH" in
|
||||
"armv8-a"|"aarch64"|"arm64-v8a"|"armv8a")
|
||||
echo -e "\e[1;32m$ARCH Libraries\e[0m"
|
||||
TARGET_ARCH="aarch64"
|
||||
TARGET_CPU="armv8-a"
|
||||
TARGET_ABI="aarch64"
|
||||
PREFIX="${FFMPEG_BUILD_DIR}/$ANDROID_API_LEVEL/arm64-v8a"
|
||||
CROSS_PREFIX="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/$TARGET_ABI-linux-android${ANDROID_API_LEVEL}-"
|
||||
EXTRA_CFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
EXTRA_CXXFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
|
||||
EXTRA_CONFIG="\
|
||||
--enable-asm \
|
||||
--enable-neon "
|
||||
;;
|
||||
"armv7-a"|"armeabi-v7a"|"armv7a")
|
||||
echo -e "\e[1;32m$ARCH Libraries\e[0m"
|
||||
TARGET_ARCH="arm"
|
||||
TARGET_CPU="armv7-a"
|
||||
TARGET_ABI="armv7a"
|
||||
PREFIX="${FFMPEG_BUILD_DIR}/$ANDROID_API_LEVEL/armeabi-v7a"
|
||||
CROSS_PREFIX="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/$TARGET_ABI-linux-androideabi${ANDROID_API_LEVEL}-"
|
||||
EXTRA_CFLAGS="-O2 -march=$TARGET_CPU -mfpu=neon -fomit-frame-pointer"
|
||||
EXTRA_CXXFLAGS="-O2 -march=$TARGET_CPU -mfpu=neon -fomit-frame-pointer"
|
||||
|
||||
EXTRA_CONFIG="\
|
||||
--disable-armv5te \
|
||||
--disable-armv6 \
|
||||
--disable-armv6t2 \
|
||||
--enable-asm \
|
||||
--enable-neon "
|
||||
;;
|
||||
"x86-64"|"x86_64")
|
||||
echo -e "\e[1;32m$ARCH Libraries\e[0m"
|
||||
TARGET_ARCH="x86_64"
|
||||
TARGET_CPU="x86-64"
|
||||
TARGET_ABI="x86_64"
|
||||
PREFIX="${FFMPEG_BUILD_DIR}/$ANDROID_API_LEVEL/x86_64"
|
||||
CROSS_PREFIX="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/$TARGET_ABI-linux-android${ANDROID_API_LEVEL}-"
|
||||
EXTRA_CFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
EXTRA_CXXFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
|
||||
EXTRA_CONFIG="\
|
||||
--enable-asm "
|
||||
;;
|
||||
"x86"|"i686")
|
||||
echo -e "\e[1;32m$ARCH Libraries\e[0m"
|
||||
TARGET_ARCH="i686"
|
||||
TARGET_CPU="i686"
|
||||
TARGET_ABI="i686"
|
||||
PREFIX="${FFMPEG_BUILD_DIR}/$ANDROID_API_LEVEL/x86"
|
||||
CROSS_PREFIX="$ANDROID_NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/$TARGET_ABI-linux-android${ANDROID_API_LEVEL}-"
|
||||
EXTRA_CFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
EXTRA_CXXFLAGS="-O2 -march=$TARGET_CPU -fomit-frame-pointer"
|
||||
EXTRA_CONFIG="\
|
||||
--disable-asm "
|
||||
;;
|
||||
* )
|
||||
echo "Unknown architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
buildLibdav1d "$TARGET_ARCH" "$TARGET_CPU" "$PREFIX" "$CROSS_PREFIX" "$EXTRA_CFLAGS" "$EXTRA_CXXFLAGS" "$EXTRA_CONFIG"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling $ARCH"
|
||||
exit 1
|
||||
fi
|
||||
configure_ffmpeg "$TARGET_ARCH" "$TARGET_CPU" "$PREFIX" "$CROSS_PREFIX" "$EXTRA_CFLAGS" "$EXTRA_CXXFLAGS" "$EXTRA_CONFIG"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error compiling $ARCH"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* AC-3 parser prototypes
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2003 Michael Niedermayer
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_AC3_PARSER_H
|
||||
#define AVCODEC_AC3_PARSER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Extract the bitstream ID and the frame size from AC-3 data.
|
||||
*/
|
||||
int av_ac3_parse_header(const uint8_t *buf, size_t size,
|
||||
uint8_t *bitstream_id, uint16_t *frame_size);
|
||||
|
||||
|
||||
#endif /* AVCODEC_AC3_PARSER_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_ADTS_PARSER_H
|
||||
#define AVCODEC_ADTS_PARSER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define AV_AAC_ADTS_HEADER_SIZE 7
|
||||
|
||||
/**
|
||||
* Extract the number of samples and frames from AAC data.
|
||||
* @param[in] buf pointer to AAC data buffer
|
||||
* @param[out] samples Pointer to where number of samples is written
|
||||
* @param[out] frames Pointer to where number of frames is written
|
||||
* @return Returns 0 on success, error code on failure.
|
||||
*/
|
||||
int av_adts_header_parse(const uint8_t *buf, uint32_t *samples,
|
||||
uint8_t *frames);
|
||||
|
||||
#endif /* AVCODEC_ADTS_PARSER_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_AVDCT_H
|
||||
#define AVCODEC_AVDCT_H
|
||||
|
||||
#include "libavutil/opt.h"
|
||||
|
||||
/**
|
||||
* AVDCT context.
|
||||
* @note function pointers can be NULL if the specific features have been
|
||||
* disabled at build time.
|
||||
*/
|
||||
typedef struct AVDCT {
|
||||
const AVClass *av_class;
|
||||
|
||||
void (*idct)(int16_t *block /* align 16 */);
|
||||
|
||||
/**
|
||||
* IDCT input permutation.
|
||||
* Several optimized IDCTs need a permutated input (relative to the
|
||||
* normal order of the reference IDCT).
|
||||
* This permutation must be performed before the idct_put/add.
|
||||
* Note, normally this can be merged with the zigzag/alternate scan<br>
|
||||
* An example to avoid confusion:
|
||||
* - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...)
|
||||
* - (x -> reference DCT -> reference IDCT -> x)
|
||||
* - (x -> reference DCT -> simple_mmx_perm = idct_permutation
|
||||
* -> simple_idct_mmx -> x)
|
||||
* - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant
|
||||
* -> simple_idct_mmx -> ...)
|
||||
*/
|
||||
uint8_t idct_permutation[64];
|
||||
|
||||
void (*fdct)(int16_t *block /* align 16 */);
|
||||
|
||||
|
||||
/**
|
||||
* DCT algorithm.
|
||||
* must use AVOptions to set this field.
|
||||
*/
|
||||
int dct_algo;
|
||||
|
||||
/**
|
||||
* IDCT algorithm.
|
||||
* must use AVOptions to set this field.
|
||||
*/
|
||||
int idct_algo;
|
||||
|
||||
void (*get_pixels)(int16_t *block /* align 16 */,
|
||||
const uint8_t *pixels /* align 8 */,
|
||||
ptrdiff_t line_size);
|
||||
|
||||
int bits_per_sample;
|
||||
|
||||
void (*get_pixels_unaligned)(int16_t *block /* align 16 */,
|
||||
const uint8_t *pixels,
|
||||
ptrdiff_t line_size);
|
||||
} AVDCT;
|
||||
|
||||
/**
|
||||
* Allocates a AVDCT context.
|
||||
* This needs to be initialized with avcodec_dct_init() after optionally
|
||||
* configuring it with AVOptions.
|
||||
*
|
||||
* To free it use av_free()
|
||||
*/
|
||||
AVDCT *avcodec_dct_alloc(void);
|
||||
int avcodec_dct_init(AVDCT *);
|
||||
|
||||
const AVClass *avcodec_dct_get_class(void);
|
||||
|
||||
#endif /* AVCODEC_AVDCT_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_AVFFT_H
|
||||
#define AVCODEC_AVFFT_H
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "version_major.h"
|
||||
#if FF_API_AVFFT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_fft
|
||||
* FFT functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lavc_fft FFT functions
|
||||
* @ingroup lavc_misc
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef float FFTSample;
|
||||
|
||||
typedef struct FFTComplex {
|
||||
FFTSample re, im;
|
||||
} FFTComplex;
|
||||
|
||||
typedef struct FFTContext FFTContext;
|
||||
|
||||
/**
|
||||
* Set up a complex FFT.
|
||||
* @param nbits log2 of the length of the input array
|
||||
* @param inverse if 0 perform the forward transform, if 1 perform the inverse
|
||||
* @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_FFT
|
||||
*/
|
||||
attribute_deprecated
|
||||
FFTContext *av_fft_init(int nbits, int inverse);
|
||||
|
||||
/**
|
||||
* Do the permutation needed BEFORE calling ff_fft_calc().
|
||||
* @deprecated without replacement
|
||||
*/
|
||||
attribute_deprecated
|
||||
void av_fft_permute(FFTContext *s, FFTComplex *z);
|
||||
|
||||
/**
|
||||
* Do a complex FFT with the parameters defined in av_fft_init(). The
|
||||
* input data must be permuted before. No 1.0/sqrt(n) normalization is done.
|
||||
* @deprecated use the av_tx_fn value returned by av_tx_init, which also does permutation
|
||||
*/
|
||||
attribute_deprecated
|
||||
void av_fft_calc(FFTContext *s, FFTComplex *z);
|
||||
|
||||
attribute_deprecated
|
||||
void av_fft_end(FFTContext *s);
|
||||
|
||||
/**
|
||||
* @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_MDCT,
|
||||
* with a flag of AV_TX_FULL_IMDCT for a replacement to av_imdct_calc.
|
||||
*/
|
||||
attribute_deprecated
|
||||
FFTContext *av_mdct_init(int nbits, int inverse, double scale);
|
||||
attribute_deprecated
|
||||
void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
attribute_deprecated
|
||||
void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
attribute_deprecated
|
||||
void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
attribute_deprecated
|
||||
void av_mdct_end(FFTContext *s);
|
||||
|
||||
/* Real Discrete Fourier Transform */
|
||||
|
||||
enum RDFTransformType {
|
||||
DFT_R2C,
|
||||
IDFT_C2R,
|
||||
IDFT_R2C,
|
||||
DFT_C2R,
|
||||
};
|
||||
|
||||
typedef struct RDFTContext RDFTContext;
|
||||
|
||||
/**
|
||||
* Set up a real FFT.
|
||||
* @param nbits log2 of the length of the input array
|
||||
* @param trans the type of transform
|
||||
*
|
||||
* @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_RDFT
|
||||
*/
|
||||
attribute_deprecated
|
||||
RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans);
|
||||
attribute_deprecated
|
||||
void av_rdft_calc(RDFTContext *s, FFTSample *data);
|
||||
attribute_deprecated
|
||||
void av_rdft_end(RDFTContext *s);
|
||||
|
||||
/* Discrete Cosine Transform */
|
||||
|
||||
typedef struct DCTContext DCTContext;
|
||||
|
||||
enum DCTTransformType {
|
||||
DCT_II = 0,
|
||||
DCT_III,
|
||||
DCT_I,
|
||||
DST_I,
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up DCT.
|
||||
*
|
||||
* @param nbits size of the input array:
|
||||
* (1 << nbits) for DCT-II, DCT-III and DST-I
|
||||
* (1 << nbits) + 1 for DCT-I
|
||||
* @param type the type of transform
|
||||
*
|
||||
* @note the first element of the input of DST-I is ignored
|
||||
*
|
||||
* @deprecated use av_tx_init from libavutil/tx.h with an appropriate type of AV_TX_FLOAT_DCT
|
||||
*/
|
||||
attribute_deprecated
|
||||
DCTContext *av_dct_init(int nbits, enum DCTTransformType type);
|
||||
attribute_deprecated
|
||||
void av_dct_calc(DCTContext *s, FFTSample *data);
|
||||
attribute_deprecated
|
||||
void av_dct_end (DCTContext *s);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* FF_API_AVFFT */
|
||||
#endif /* AVCODEC_AVFFT_H */
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Bitstream filters public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_BSF_H
|
||||
#define AVCODEC_BSF_H
|
||||
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/rational.h"
|
||||
|
||||
#include "codec_id.h"
|
||||
#include "codec_par.h"
|
||||
#include "packet.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavc_bsf Bitstream filters
|
||||
* @ingroup libavc
|
||||
*
|
||||
* Bitstream filters transform encoded media data without decoding it. This
|
||||
* allows e.g. manipulating various header values. Bitstream filters operate on
|
||||
* @ref AVPacket "AVPackets".
|
||||
*
|
||||
* The bitstream filtering API is centered around two structures:
|
||||
* AVBitStreamFilter and AVBSFContext. The former represents a bitstream filter
|
||||
* in abstract, the latter a specific filtering process. Obtain an
|
||||
* AVBitStreamFilter using av_bsf_get_by_name() or av_bsf_iterate(), then pass
|
||||
* it to av_bsf_alloc() to create an AVBSFContext. Fill in the user-settable
|
||||
* AVBSFContext fields, as described in its documentation, then call
|
||||
* av_bsf_init() to prepare the filter context for use.
|
||||
*
|
||||
* Submit packets for filtering using av_bsf_send_packet(), obtain filtered
|
||||
* results with av_bsf_receive_packet(). When no more input packets will be
|
||||
* sent, submit a NULL AVPacket to signal the end of the stream to the filter.
|
||||
* av_bsf_receive_packet() will then return trailing packets, if any are
|
||||
* produced by the filter.
|
||||
*
|
||||
* Finally, free the filter context with av_bsf_free().
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* The bitstream filter state.
|
||||
*
|
||||
* This struct must be allocated with av_bsf_alloc() and freed with
|
||||
* av_bsf_free().
|
||||
*
|
||||
* The fields in the struct will only be changed (by the caller or by the
|
||||
* filter) as described in their documentation, and are to be considered
|
||||
* immutable otherwise.
|
||||
*/
|
||||
typedef struct AVBSFContext {
|
||||
/**
|
||||
* A class for logging and AVOptions
|
||||
*/
|
||||
const AVClass *av_class;
|
||||
|
||||
/**
|
||||
* The bitstream filter this context is an instance of.
|
||||
*/
|
||||
const struct AVBitStreamFilter *filter;
|
||||
|
||||
/**
|
||||
* Opaque filter-specific private data. If filter->priv_class is non-NULL,
|
||||
* this is an AVOptions-enabled struct.
|
||||
*/
|
||||
void *priv_data;
|
||||
|
||||
/**
|
||||
* Parameters of the input stream. This field is allocated in
|
||||
* av_bsf_alloc(), it needs to be filled by the caller before
|
||||
* av_bsf_init().
|
||||
*/
|
||||
AVCodecParameters *par_in;
|
||||
|
||||
/**
|
||||
* Parameters of the output stream. This field is allocated in
|
||||
* av_bsf_alloc(), it is set by the filter in av_bsf_init().
|
||||
*/
|
||||
AVCodecParameters *par_out;
|
||||
|
||||
/**
|
||||
* The timebase used for the timestamps of the input packets. Set by the
|
||||
* caller before av_bsf_init().
|
||||
*/
|
||||
AVRational time_base_in;
|
||||
|
||||
/**
|
||||
* The timebase used for the timestamps of the output packets. Set by the
|
||||
* filter in av_bsf_init().
|
||||
*/
|
||||
AVRational time_base_out;
|
||||
} AVBSFContext;
|
||||
|
||||
typedef struct AVBitStreamFilter {
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* A list of codec ids supported by the filter, terminated by
|
||||
* AV_CODEC_ID_NONE.
|
||||
* May be NULL, in that case the bitstream filter works with any codec id.
|
||||
*/
|
||||
const enum AVCodecID *codec_ids;
|
||||
|
||||
/**
|
||||
* A class for the private data, used to declare bitstream filter private
|
||||
* AVOptions. This field is NULL for bitstream filters that do not declare
|
||||
* any options.
|
||||
*
|
||||
* If this field is non-NULL, the first member of the filter private data
|
||||
* must be a pointer to AVClass, which will be set by libavcodec generic
|
||||
* code to this class.
|
||||
*/
|
||||
const AVClass *priv_class;
|
||||
} AVBitStreamFilter;
|
||||
|
||||
/**
|
||||
* @return a bitstream filter with the specified name or NULL if no such
|
||||
* bitstream filter exists.
|
||||
*/
|
||||
const AVBitStreamFilter *av_bsf_get_by_name(const char *name);
|
||||
|
||||
/**
|
||||
* Iterate over all registered bitstream filters.
|
||||
*
|
||||
* @param opaque a pointer where libavcodec will store the iteration state. Must
|
||||
* point to NULL to start the iteration.
|
||||
*
|
||||
* @return the next registered bitstream filter or NULL when the iteration is
|
||||
* finished
|
||||
*/
|
||||
const AVBitStreamFilter *av_bsf_iterate(void **opaque);
|
||||
|
||||
/**
|
||||
* Allocate a context for a given bitstream filter. The caller must fill in the
|
||||
* context parameters as described in the documentation and then call
|
||||
* av_bsf_init() before sending any data to the filter.
|
||||
*
|
||||
* @param filter the filter for which to allocate an instance.
|
||||
* @param[out] ctx a pointer into which the pointer to the newly-allocated context
|
||||
* will be written. It must be freed with av_bsf_free() after the
|
||||
* filtering is done.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR code on failure
|
||||
*/
|
||||
int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx);
|
||||
|
||||
/**
|
||||
* Prepare the filter for use, after all the parameters and options have been
|
||||
* set.
|
||||
*
|
||||
* @param ctx a AVBSFContext previously allocated with av_bsf_alloc()
|
||||
*/
|
||||
int av_bsf_init(AVBSFContext *ctx);
|
||||
|
||||
/**
|
||||
* Submit a packet for filtering.
|
||||
*
|
||||
* After sending each packet, the filter must be completely drained by calling
|
||||
* av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or
|
||||
* AVERROR_EOF.
|
||||
*
|
||||
* @param ctx an initialized AVBSFContext
|
||||
* @param pkt the packet to filter. The bitstream filter will take ownership of
|
||||
* the packet and reset the contents of pkt. pkt is not touched if an error occurs.
|
||||
* If pkt is empty (i.e. NULL, or pkt->data is NULL and pkt->side_data_elems zero),
|
||||
* it signals the end of the stream (i.e. no more non-empty packets will be sent;
|
||||
* sending more empty packets does nothing) and will cause the filter to output
|
||||
* any packets it may have buffered internally.
|
||||
*
|
||||
* @return
|
||||
* - 0 on success.
|
||||
* - AVERROR(EAGAIN) if packets need to be retrieved from the filter (using
|
||||
* av_bsf_receive_packet()) before new input can be consumed.
|
||||
* - Another negative AVERROR value if an error occurs.
|
||||
*/
|
||||
int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Retrieve a filtered packet.
|
||||
*
|
||||
* @param ctx an initialized AVBSFContext
|
||||
* @param[out] pkt this struct will be filled with the contents of the filtered
|
||||
* packet. It is owned by the caller and must be freed using
|
||||
* av_packet_unref() when it is no longer needed.
|
||||
* This parameter should be "clean" (i.e. freshly allocated
|
||||
* with av_packet_alloc() or unreffed with av_packet_unref())
|
||||
* when this function is called. If this function returns
|
||||
* successfully, the contents of pkt will be completely
|
||||
* overwritten by the returned data. On failure, pkt is not
|
||||
* touched.
|
||||
*
|
||||
* @return
|
||||
* - 0 on success.
|
||||
* - AVERROR(EAGAIN) if more packets need to be sent to the filter (using
|
||||
* av_bsf_send_packet()) to get more output.
|
||||
* - AVERROR_EOF if there will be no further output from the filter.
|
||||
* - Another negative AVERROR value if an error occurs.
|
||||
*
|
||||
* @note one input packet may result in several output packets, so after sending
|
||||
* a packet with av_bsf_send_packet(), this function needs to be called
|
||||
* repeatedly until it stops returning 0. It is also possible for a filter to
|
||||
* output fewer packets than were sent to it, so this function may return
|
||||
* AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call.
|
||||
*/
|
||||
int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Reset the internal bitstream filter state. Should be called e.g. when seeking.
|
||||
*/
|
||||
void av_bsf_flush(AVBSFContext *ctx);
|
||||
|
||||
/**
|
||||
* Free a bitstream filter context and everything associated with it; write NULL
|
||||
* into the supplied pointer.
|
||||
*/
|
||||
void av_bsf_free(AVBSFContext **ctx);
|
||||
|
||||
/**
|
||||
* Get the AVClass for AVBSFContext. It can be used in combination with
|
||||
* AV_OPT_SEARCH_FAKE_OBJ for examining options.
|
||||
*
|
||||
* @see av_opt_find().
|
||||
*/
|
||||
const AVClass *av_bsf_get_class(void);
|
||||
|
||||
/**
|
||||
* Structure for chain/list of bitstream filters.
|
||||
* Empty list can be allocated by av_bsf_list_alloc().
|
||||
*/
|
||||
typedef struct AVBSFList AVBSFList;
|
||||
|
||||
/**
|
||||
* Allocate empty list of bitstream filters.
|
||||
* The list must be later freed by av_bsf_list_free()
|
||||
* or finalized by av_bsf_list_finalize().
|
||||
*
|
||||
* @return Pointer to @ref AVBSFList on success, NULL in case of failure
|
||||
*/
|
||||
AVBSFList *av_bsf_list_alloc(void);
|
||||
|
||||
/**
|
||||
* Free list of bitstream filters.
|
||||
*
|
||||
* @param lst Pointer to pointer returned by av_bsf_list_alloc()
|
||||
*/
|
||||
void av_bsf_list_free(AVBSFList **lst);
|
||||
|
||||
/**
|
||||
* Append bitstream filter to the list of bitstream filters.
|
||||
*
|
||||
* @param lst List to append to
|
||||
* @param bsf Filter context to be appended
|
||||
*
|
||||
* @return >=0 on success, negative AVERROR in case of failure
|
||||
*/
|
||||
int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf);
|
||||
|
||||
/**
|
||||
* Construct new bitstream filter context given it's name and options
|
||||
* and append it to the list of bitstream filters.
|
||||
*
|
||||
* @param lst List to append to
|
||||
* @param bsf_name Name of the bitstream filter
|
||||
* @param options Options for the bitstream filter, can be set to NULL
|
||||
*
|
||||
* @return >=0 on success, negative AVERROR in case of failure
|
||||
*/
|
||||
int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary **options);
|
||||
/**
|
||||
* Finalize list of bitstream filters.
|
||||
*
|
||||
* This function will transform @ref AVBSFList to single @ref AVBSFContext,
|
||||
* so the whole chain of bitstream filters can be treated as single filter
|
||||
* freshly allocated by av_bsf_alloc().
|
||||
* If the call is successful, @ref AVBSFList structure is freed and lst
|
||||
* will be set to NULL. In case of failure, caller is responsible for
|
||||
* freeing the structure by av_bsf_list_free()
|
||||
*
|
||||
* @param lst Filter list structure to be transformed
|
||||
* @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure
|
||||
* representing the chain of bitstream filters
|
||||
*
|
||||
* @return >=0 on success, negative AVERROR in case of failure
|
||||
*/
|
||||
int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf);
|
||||
|
||||
/**
|
||||
* Parse string describing list of bitstream filters and create single
|
||||
* @ref AVBSFContext describing the whole chain of bitstream filters.
|
||||
* Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext freshly
|
||||
* allocated by av_bsf_alloc().
|
||||
*
|
||||
* @param str String describing chain of bitstream filters in format
|
||||
* `bsf1[=opt1=val1:opt2=val2][,bsf2]`
|
||||
* @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure
|
||||
* representing the chain of bitstream filters
|
||||
*
|
||||
* @return >=0 on success, negative AVERROR in case of failure
|
||||
*/
|
||||
int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf);
|
||||
|
||||
/**
|
||||
* Get null/pass-through bitstream filter.
|
||||
*
|
||||
* @param[out] bsf Pointer to be set to new instance of pass-through bitstream filter
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int av_bsf_get_null_filter(AVBSFContext **bsf);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // AVCODEC_BSF_H
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* AVCodec public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_CODEC_H
|
||||
#define AVCODEC_CODEC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/hwcontext.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
|
||||
#include "libavcodec/codec_id.h"
|
||||
#include "libavcodec/version_major.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavc_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decoder can use draw_horiz_band callback.
|
||||
*/
|
||||
#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0)
|
||||
/**
|
||||
* Codec uses get_buffer() or get_encode_buffer() for allocating buffers and
|
||||
* supports custom allocators.
|
||||
* If not set, it might not use get_buffer() or get_encode_buffer() at all, or
|
||||
* use operations that assume the buffer was allocated by
|
||||
* avcodec_default_get_buffer2 or avcodec_default_get_encode_buffer.
|
||||
*/
|
||||
#define AV_CODEC_CAP_DR1 (1 << 1)
|
||||
/**
|
||||
* Encoder or decoder requires flushing with NULL input at the end in order to
|
||||
* give the complete and correct output.
|
||||
*
|
||||
* NOTE: If this flag is not set, the codec is guaranteed to never be fed with
|
||||
* with NULL data. The user can still send NULL data to the public encode
|
||||
* or decode function, but libavcodec will not pass it along to the codec
|
||||
* unless this flag is set.
|
||||
*
|
||||
* Decoders:
|
||||
* The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL,
|
||||
* avpkt->size=0 at the end to get the delayed data until the decoder no longer
|
||||
* returns frames.
|
||||
*
|
||||
* Encoders:
|
||||
* The encoder needs to be fed with NULL data at the end of encoding until the
|
||||
* encoder no longer returns data.
|
||||
*
|
||||
* NOTE: For encoders implementing the AVCodec.encode2() function, setting this
|
||||
* flag also means that the encoder must set the pts and duration for
|
||||
* each output packet. If this flag is not set, the pts and duration will
|
||||
* be determined by libavcodec from the input frame.
|
||||
*/
|
||||
#define AV_CODEC_CAP_DELAY (1 << 5)
|
||||
/**
|
||||
* Codec can be fed a final frame with a smaller size.
|
||||
* This can be used to prevent truncation of the last audio samples.
|
||||
*/
|
||||
#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6)
|
||||
|
||||
#if FF_API_SUBFRAMES
|
||||
/**
|
||||
* Codec can output multiple frames per AVPacket
|
||||
* Normally demuxers return one frame at a time, demuxers which do not do
|
||||
* are connected to a parser to split what they return into proper frames.
|
||||
* This flag is reserved to the very rare category of codecs which have a
|
||||
* bitstream that cannot be split into frames without timeconsuming
|
||||
* operations like full decoding. Demuxers carrying such bitstreams thus
|
||||
* may return multiple frames in a packet. This has many disadvantages like
|
||||
* prohibiting stream copy in many cases thus it should only be considered
|
||||
* as a last resort.
|
||||
*/
|
||||
#define AV_CODEC_CAP_SUBFRAMES (1 << 8)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Codec is experimental and is thus avoided in favor of non experimental
|
||||
* encoders
|
||||
*/
|
||||
#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9)
|
||||
/**
|
||||
* Codec should fill in channel configuration and samplerate instead of container
|
||||
*/
|
||||
#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10)
|
||||
/**
|
||||
* Codec supports frame-level multithreading.
|
||||
*/
|
||||
#define AV_CODEC_CAP_FRAME_THREADS (1 << 12)
|
||||
/**
|
||||
* Codec supports slice-based (or partition-based) multithreading.
|
||||
*/
|
||||
#define AV_CODEC_CAP_SLICE_THREADS (1 << 13)
|
||||
/**
|
||||
* Codec supports changed parameters at any point.
|
||||
*/
|
||||
#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14)
|
||||
/**
|
||||
* Codec supports multithreading through a method other than slice- or
|
||||
* frame-level multithreading. Typically this marks wrappers around
|
||||
* multithreading-capable external libraries.
|
||||
*/
|
||||
#define AV_CODEC_CAP_OTHER_THREADS (1 << 15)
|
||||
/**
|
||||
* Audio encoder supports receiving a different number of samples in each call.
|
||||
*/
|
||||
#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16)
|
||||
/**
|
||||
* Decoder is not a preferred choice for probing.
|
||||
* This indicates that the decoder is not a good choice for probing.
|
||||
* It could for example be an expensive to spin up hardware decoder,
|
||||
* or it could simply not provide a lot of useful information about
|
||||
* the stream.
|
||||
* A decoder marked with this flag should only be used as last resort
|
||||
* choice for probing.
|
||||
*/
|
||||
#define AV_CODEC_CAP_AVOID_PROBING (1 << 17)
|
||||
|
||||
/**
|
||||
* Codec is backed by a hardware implementation. Typically used to
|
||||
* identify a non-hwaccel hardware decoder. For information about hwaccels, use
|
||||
* avcodec_get_hw_config() instead.
|
||||
*/
|
||||
#define AV_CODEC_CAP_HARDWARE (1 << 18)
|
||||
|
||||
/**
|
||||
* Codec is potentially backed by a hardware implementation, but not
|
||||
* necessarily. This is used instead of AV_CODEC_CAP_HARDWARE, if the
|
||||
* implementation provides some sort of internal fallback.
|
||||
*/
|
||||
#define AV_CODEC_CAP_HYBRID (1 << 19)
|
||||
|
||||
/**
|
||||
* This encoder can reorder user opaque values from input AVFrames and return
|
||||
* them with corresponding output packets.
|
||||
* @see AV_CODEC_FLAG_COPY_OPAQUE
|
||||
*/
|
||||
#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 20)
|
||||
|
||||
/**
|
||||
* This encoder can be flushed using avcodec_flush_buffers(). If this flag is
|
||||
* not set, the encoder must be closed and reopened to ensure that no frames
|
||||
* remain pending.
|
||||
*/
|
||||
#define AV_CODEC_CAP_ENCODER_FLUSH (1 << 21)
|
||||
|
||||
/**
|
||||
* The encoder is able to output reconstructed frame data, i.e. raw frames that
|
||||
* would be produced by decoding the encoded bitstream.
|
||||
*
|
||||
* Reconstructed frame output is enabled by the AV_CODEC_FLAG_RECON_FRAME flag.
|
||||
*/
|
||||
#define AV_CODEC_CAP_ENCODER_RECON_FRAME (1 << 22)
|
||||
|
||||
/**
|
||||
* AVProfile.
|
||||
*/
|
||||
typedef struct AVProfile {
|
||||
int profile;
|
||||
const char *name; ///< short name for the profile
|
||||
} AVProfile;
|
||||
|
||||
/**
|
||||
* AVCodec.
|
||||
*/
|
||||
typedef struct AVCodec {
|
||||
/**
|
||||
* Name of the codec implementation.
|
||||
* The name is globally unique among encoders and among decoders (but an
|
||||
* encoder and a decoder can share the same name).
|
||||
* This is the primary way to find a codec from the user perspective.
|
||||
*/
|
||||
const char *name;
|
||||
/**
|
||||
* Descriptive name for the codec, meant to be more human readable than name.
|
||||
* You should use the NULL_IF_CONFIG_SMALL() macro to define it.
|
||||
*/
|
||||
const char *long_name;
|
||||
enum AVMediaType type;
|
||||
enum AVCodecID id;
|
||||
/**
|
||||
* Codec capabilities.
|
||||
* see AV_CODEC_CAP_*
|
||||
*/
|
||||
int capabilities;
|
||||
uint8_t max_lowres; ///< maximum value for lowres supported by the decoder
|
||||
|
||||
/**
|
||||
* Deprecated codec capabilities.
|
||||
*/
|
||||
attribute_deprecated
|
||||
const AVRational *supported_framerates; ///< @deprecated use avcodec_get_supported_config()
|
||||
attribute_deprecated
|
||||
const enum AVPixelFormat *pix_fmts; ///< @deprecated use avcodec_get_supported_config()
|
||||
attribute_deprecated
|
||||
const int *supported_samplerates; ///< @deprecated use avcodec_get_supported_config()
|
||||
attribute_deprecated
|
||||
const enum AVSampleFormat *sample_fmts; ///< @deprecated use avcodec_get_supported_config()
|
||||
|
||||
const AVClass *priv_class; ///< AVClass for the private context
|
||||
const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN}
|
||||
|
||||
/**
|
||||
* Group name of the codec implementation.
|
||||
* This is a short symbolic name of the wrapper backing this codec. A
|
||||
* wrapper uses some kind of external implementation for the codec, such
|
||||
* as an external library, or a codec implementation provided by the OS or
|
||||
* the hardware.
|
||||
* If this field is NULL, this is a builtin, libavcodec native codec.
|
||||
* If non-NULL, this will be the suffix in AVCodec.name in most cases
|
||||
* (usually AVCodec.name will be of the form "<codec_name>_<wrapper_name>").
|
||||
*/
|
||||
const char *wrapper_name;
|
||||
|
||||
/**
|
||||
* Array of supported channel layouts, terminated with a zeroed layout.
|
||||
* @deprecated use avcodec_get_supported_config()
|
||||
*/
|
||||
attribute_deprecated
|
||||
const AVChannelLayout *ch_layouts;
|
||||
} AVCodec;
|
||||
|
||||
/**
|
||||
* Iterate over all registered codecs.
|
||||
*
|
||||
* @param opaque a pointer where libavcodec will store the iteration state. Must
|
||||
* point to NULL to start the iteration.
|
||||
*
|
||||
* @return the next registered codec or NULL when the iteration is
|
||||
* finished
|
||||
*/
|
||||
const AVCodec *av_codec_iterate(void **opaque);
|
||||
|
||||
/**
|
||||
* Find a registered decoder with a matching codec ID.
|
||||
*
|
||||
* @param id AVCodecID of the requested decoder
|
||||
* @return A decoder if one was found, NULL otherwise.
|
||||
*/
|
||||
const AVCodec *avcodec_find_decoder(enum AVCodecID id);
|
||||
|
||||
/**
|
||||
* Find a registered decoder with the specified name.
|
||||
*
|
||||
* @param name name of the requested decoder
|
||||
* @return A decoder if one was found, NULL otherwise.
|
||||
*/
|
||||
const AVCodec *avcodec_find_decoder_by_name(const char *name);
|
||||
|
||||
/**
|
||||
* Find a registered encoder with a matching codec ID.
|
||||
*
|
||||
* @param id AVCodecID of the requested encoder
|
||||
* @return An encoder if one was found, NULL otherwise.
|
||||
*/
|
||||
const AVCodec *avcodec_find_encoder(enum AVCodecID id);
|
||||
|
||||
/**
|
||||
* Find a registered encoder with the specified name.
|
||||
*
|
||||
* @param name name of the requested encoder
|
||||
* @return An encoder if one was found, NULL otherwise.
|
||||
*/
|
||||
const AVCodec *avcodec_find_encoder_by_name(const char *name);
|
||||
/**
|
||||
* @return a non-zero number if codec is an encoder, zero otherwise
|
||||
*/
|
||||
int av_codec_is_encoder(const AVCodec *codec);
|
||||
|
||||
/**
|
||||
* @return a non-zero number if codec is a decoder, zero otherwise
|
||||
*/
|
||||
int av_codec_is_decoder(const AVCodec *codec);
|
||||
|
||||
/**
|
||||
* Return a name for the specified profile, if available.
|
||||
*
|
||||
* @param codec the codec that is searched for the given profile
|
||||
* @param profile the profile value for which a name is requested
|
||||
* @return A name for the profile if found, NULL otherwise.
|
||||
*/
|
||||
const char *av_get_profile_name(const AVCodec *codec, int profile);
|
||||
|
||||
enum {
|
||||
/**
|
||||
* The codec supports this format via the hw_device_ctx interface.
|
||||
*
|
||||
* When selecting this format, AVCodecContext.hw_device_ctx should
|
||||
* have been set to a device of the specified type before calling
|
||||
* avcodec_open2().
|
||||
*/
|
||||
AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX = 0x01,
|
||||
/**
|
||||
* The codec supports this format via the hw_frames_ctx interface.
|
||||
*
|
||||
* When selecting this format for a decoder,
|
||||
* AVCodecContext.hw_frames_ctx should be set to a suitable frames
|
||||
* context inside the get_format() callback. The frames context
|
||||
* must have been created on a device of the specified type.
|
||||
*
|
||||
* When selecting this format for an encoder,
|
||||
* AVCodecContext.hw_frames_ctx should be set to the context which
|
||||
* will be used for the input frames before calling avcodec_open2().
|
||||
*/
|
||||
AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX = 0x02,
|
||||
/**
|
||||
* The codec supports this format by some internal method.
|
||||
*
|
||||
* This format can be selected without any additional configuration -
|
||||
* no device or frames context is required.
|
||||
*/
|
||||
AV_CODEC_HW_CONFIG_METHOD_INTERNAL = 0x04,
|
||||
/**
|
||||
* The codec supports this format by some ad-hoc method.
|
||||
*
|
||||
* Additional settings and/or function calls are required. See the
|
||||
* codec-specific documentation for details. (Methods requiring
|
||||
* this sort of configuration are deprecated and others should be
|
||||
* used in preference.)
|
||||
*/
|
||||
AV_CODEC_HW_CONFIG_METHOD_AD_HOC = 0x08,
|
||||
};
|
||||
|
||||
typedef struct AVCodecHWConfig {
|
||||
/**
|
||||
* For decoders, a hardware pixel format which that decoder may be
|
||||
* able to decode to if suitable hardware is available.
|
||||
*
|
||||
* For encoders, a pixel format which the encoder may be able to
|
||||
* accept. If set to AV_PIX_FMT_NONE, this applies to all pixel
|
||||
* formats supported by the codec.
|
||||
*/
|
||||
enum AVPixelFormat pix_fmt;
|
||||
/**
|
||||
* Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible
|
||||
* setup methods which can be used with this configuration.
|
||||
*/
|
||||
int methods;
|
||||
/**
|
||||
* The device type associated with the configuration.
|
||||
*
|
||||
* Must be set for AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX and
|
||||
* AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, otherwise unused.
|
||||
*/
|
||||
enum AVHWDeviceType device_type;
|
||||
} AVCodecHWConfig;
|
||||
|
||||
/**
|
||||
* Retrieve supported hardware configurations for a codec.
|
||||
*
|
||||
* Values of index from zero to some maximum return the indexed configuration
|
||||
* descriptor; all other values return NULL. If the codec does not support
|
||||
* any hardware configurations then it will always return NULL.
|
||||
*/
|
||||
const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVCODEC_CODEC_H */
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Codec descriptors public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_CODEC_DESC_H
|
||||
#define AVCODEC_CODEC_DESC_H
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
|
||||
#include "codec_id.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavc_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* This struct describes the properties of a single codec described by an
|
||||
* AVCodecID.
|
||||
* @see avcodec_descriptor_get()
|
||||
*/
|
||||
typedef struct AVCodecDescriptor {
|
||||
enum AVCodecID id;
|
||||
enum AVMediaType type;
|
||||
/**
|
||||
* Name of the codec described by this descriptor. It is non-empty and
|
||||
* unique for each codec descriptor. It should contain alphanumeric
|
||||
* characters and '_' only.
|
||||
*/
|
||||
const char *name;
|
||||
/**
|
||||
* A more descriptive name for this codec. May be NULL.
|
||||
*/
|
||||
const char *long_name;
|
||||
/**
|
||||
* Codec properties, a combination of AV_CODEC_PROP_* flags.
|
||||
*/
|
||||
int props;
|
||||
/**
|
||||
* MIME type(s) associated with the codec.
|
||||
* May be NULL; if not, a NULL-terminated array of MIME types.
|
||||
* The first item is always non-NULL and is the preferred MIME type.
|
||||
*/
|
||||
const char *const *mime_types;
|
||||
/**
|
||||
* If non-NULL, an array of profiles recognized for this codec.
|
||||
* Terminated with AV_PROFILE_UNKNOWN.
|
||||
*/
|
||||
const struct AVProfile *profiles;
|
||||
} AVCodecDescriptor;
|
||||
|
||||
/**
|
||||
* Codec uses only intra compression.
|
||||
* Video and audio codecs only.
|
||||
*/
|
||||
#define AV_CODEC_PROP_INTRA_ONLY (1 << 0)
|
||||
/**
|
||||
* Codec supports lossy compression. Audio and video codecs only.
|
||||
* @note a codec may support both lossy and lossless
|
||||
* compression modes
|
||||
*/
|
||||
#define AV_CODEC_PROP_LOSSY (1 << 1)
|
||||
/**
|
||||
* Codec supports lossless compression. Audio and video codecs only.
|
||||
*/
|
||||
#define AV_CODEC_PROP_LOSSLESS (1 << 2)
|
||||
/**
|
||||
* Codec supports frame reordering. That is, the coded order (the order in which
|
||||
* the encoded packets are output by the encoders / stored / input to the
|
||||
* decoders) may be different from the presentation order of the corresponding
|
||||
* frames.
|
||||
*
|
||||
* For codecs that do not have this property set, PTS and DTS should always be
|
||||
* equal.
|
||||
*/
|
||||
#define AV_CODEC_PROP_REORDER (1 << 3)
|
||||
|
||||
/**
|
||||
* Video codec supports separate coding of fields in interlaced frames.
|
||||
*/
|
||||
#define AV_CODEC_PROP_FIELDS (1 << 4)
|
||||
|
||||
/**
|
||||
* Subtitle codec is bitmap based
|
||||
* Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field.
|
||||
*/
|
||||
#define AV_CODEC_PROP_BITMAP_SUB (1 << 16)
|
||||
/**
|
||||
* Subtitle codec is text based.
|
||||
* Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field.
|
||||
*/
|
||||
#define AV_CODEC_PROP_TEXT_SUB (1 << 17)
|
||||
|
||||
/**
|
||||
* @return descriptor for given codec ID or NULL if no descriptor exists.
|
||||
*/
|
||||
const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id);
|
||||
|
||||
/**
|
||||
* Iterate over all codec descriptors known to libavcodec.
|
||||
*
|
||||
* @param prev previous descriptor. NULL to get the first descriptor.
|
||||
*
|
||||
* @return next descriptor or NULL after the last descriptor
|
||||
*/
|
||||
const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev);
|
||||
|
||||
/**
|
||||
* @return codec descriptor with the given name or NULL if no such descriptor
|
||||
* exists.
|
||||
*/
|
||||
const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // AVCODEC_CODEC_DESC_H
|
||||
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
* Codec IDs
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_CODEC_ID_H
|
||||
#define AVCODEC_CODEC_ID_H
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
|
||||
#include "version_major.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavc_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Identify the syntax and semantics of the bitstream.
|
||||
* The principle is roughly:
|
||||
* Two decoders with the same ID can decode the same streams.
|
||||
* Two encoders with the same ID can encode compatible streams.
|
||||
* There may be slight deviations from the principle due to implementation
|
||||
* details.
|
||||
*
|
||||
* If you add a codec ID to this list, add it so that
|
||||
* 1. no value of an existing codec ID changes (that would break ABI),
|
||||
* 2. it is as close as possible to similar codecs
|
||||
*
|
||||
* After adding new codec IDs, do not forget to add an entry to the codec
|
||||
* descriptor list and bump libavcodec minor version.
|
||||
*/
|
||||
enum AVCodecID {
|
||||
AV_CODEC_ID_NONE,
|
||||
|
||||
/* video codecs */
|
||||
AV_CODEC_ID_MPEG1VIDEO,
|
||||
AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
|
||||
AV_CODEC_ID_H261,
|
||||
AV_CODEC_ID_H263,
|
||||
AV_CODEC_ID_RV10,
|
||||
AV_CODEC_ID_RV20,
|
||||
AV_CODEC_ID_MJPEG,
|
||||
AV_CODEC_ID_MJPEGB,
|
||||
AV_CODEC_ID_LJPEG,
|
||||
AV_CODEC_ID_SP5X,
|
||||
AV_CODEC_ID_JPEGLS,
|
||||
AV_CODEC_ID_MPEG4,
|
||||
AV_CODEC_ID_RAWVIDEO,
|
||||
AV_CODEC_ID_MSMPEG4V1,
|
||||
AV_CODEC_ID_MSMPEG4V2,
|
||||
AV_CODEC_ID_MSMPEG4V3,
|
||||
AV_CODEC_ID_WMV1,
|
||||
AV_CODEC_ID_WMV2,
|
||||
AV_CODEC_ID_H263P,
|
||||
AV_CODEC_ID_H263I,
|
||||
AV_CODEC_ID_FLV1,
|
||||
AV_CODEC_ID_SVQ1,
|
||||
AV_CODEC_ID_SVQ3,
|
||||
AV_CODEC_ID_DVVIDEO,
|
||||
AV_CODEC_ID_HUFFYUV,
|
||||
AV_CODEC_ID_CYUV,
|
||||
AV_CODEC_ID_H264,
|
||||
AV_CODEC_ID_INDEO3,
|
||||
AV_CODEC_ID_VP3,
|
||||
AV_CODEC_ID_THEORA,
|
||||
AV_CODEC_ID_ASV1,
|
||||
AV_CODEC_ID_ASV2,
|
||||
AV_CODEC_ID_FFV1,
|
||||
AV_CODEC_ID_4XM,
|
||||
AV_CODEC_ID_VCR1,
|
||||
AV_CODEC_ID_CLJR,
|
||||
AV_CODEC_ID_MDEC,
|
||||
AV_CODEC_ID_ROQ,
|
||||
AV_CODEC_ID_INTERPLAY_VIDEO,
|
||||
AV_CODEC_ID_XAN_WC3,
|
||||
AV_CODEC_ID_XAN_WC4,
|
||||
AV_CODEC_ID_RPZA,
|
||||
AV_CODEC_ID_CINEPAK,
|
||||
AV_CODEC_ID_WS_VQA,
|
||||
AV_CODEC_ID_MSRLE,
|
||||
AV_CODEC_ID_MSVIDEO1,
|
||||
AV_CODEC_ID_IDCIN,
|
||||
AV_CODEC_ID_8BPS,
|
||||
AV_CODEC_ID_SMC,
|
||||
AV_CODEC_ID_FLIC,
|
||||
AV_CODEC_ID_TRUEMOTION1,
|
||||
AV_CODEC_ID_VMDVIDEO,
|
||||
AV_CODEC_ID_MSZH,
|
||||
AV_CODEC_ID_ZLIB,
|
||||
AV_CODEC_ID_QTRLE,
|
||||
AV_CODEC_ID_TSCC,
|
||||
AV_CODEC_ID_ULTI,
|
||||
AV_CODEC_ID_QDRAW,
|
||||
AV_CODEC_ID_VIXL,
|
||||
AV_CODEC_ID_QPEG,
|
||||
AV_CODEC_ID_PNG,
|
||||
AV_CODEC_ID_PPM,
|
||||
AV_CODEC_ID_PBM,
|
||||
AV_CODEC_ID_PGM,
|
||||
AV_CODEC_ID_PGMYUV,
|
||||
AV_CODEC_ID_PAM,
|
||||
AV_CODEC_ID_FFVHUFF,
|
||||
AV_CODEC_ID_RV30,
|
||||
AV_CODEC_ID_RV40,
|
||||
AV_CODEC_ID_VC1,
|
||||
AV_CODEC_ID_WMV3,
|
||||
AV_CODEC_ID_LOCO,
|
||||
AV_CODEC_ID_WNV1,
|
||||
AV_CODEC_ID_AASC,
|
||||
AV_CODEC_ID_INDEO2,
|
||||
AV_CODEC_ID_FRAPS,
|
||||
AV_CODEC_ID_TRUEMOTION2,
|
||||
AV_CODEC_ID_BMP,
|
||||
AV_CODEC_ID_CSCD,
|
||||
AV_CODEC_ID_MMVIDEO,
|
||||
AV_CODEC_ID_ZMBV,
|
||||
AV_CODEC_ID_AVS,
|
||||
AV_CODEC_ID_SMACKVIDEO,
|
||||
AV_CODEC_ID_NUV,
|
||||
AV_CODEC_ID_KMVC,
|
||||
AV_CODEC_ID_FLASHSV,
|
||||
AV_CODEC_ID_CAVS,
|
||||
AV_CODEC_ID_JPEG2000,
|
||||
AV_CODEC_ID_VMNC,
|
||||
AV_CODEC_ID_VP5,
|
||||
AV_CODEC_ID_VP6,
|
||||
AV_CODEC_ID_VP6F,
|
||||
AV_CODEC_ID_TARGA,
|
||||
AV_CODEC_ID_DSICINVIDEO,
|
||||
AV_CODEC_ID_TIERTEXSEQVIDEO,
|
||||
AV_CODEC_ID_TIFF,
|
||||
AV_CODEC_ID_GIF,
|
||||
AV_CODEC_ID_DXA,
|
||||
AV_CODEC_ID_DNXHD,
|
||||
AV_CODEC_ID_THP,
|
||||
AV_CODEC_ID_SGI,
|
||||
AV_CODEC_ID_C93,
|
||||
AV_CODEC_ID_BETHSOFTVID,
|
||||
AV_CODEC_ID_PTX,
|
||||
AV_CODEC_ID_TXD,
|
||||
AV_CODEC_ID_VP6A,
|
||||
AV_CODEC_ID_AMV,
|
||||
AV_CODEC_ID_VB,
|
||||
AV_CODEC_ID_PCX,
|
||||
AV_CODEC_ID_SUNRAST,
|
||||
AV_CODEC_ID_INDEO4,
|
||||
AV_CODEC_ID_INDEO5,
|
||||
AV_CODEC_ID_MIMIC,
|
||||
AV_CODEC_ID_RL2,
|
||||
AV_CODEC_ID_ESCAPE124,
|
||||
AV_CODEC_ID_DIRAC,
|
||||
AV_CODEC_ID_BFI,
|
||||
AV_CODEC_ID_CMV,
|
||||
AV_CODEC_ID_MOTIONPIXELS,
|
||||
AV_CODEC_ID_TGV,
|
||||
AV_CODEC_ID_TGQ,
|
||||
AV_CODEC_ID_TQI,
|
||||
AV_CODEC_ID_AURA,
|
||||
AV_CODEC_ID_AURA2,
|
||||
AV_CODEC_ID_V210X,
|
||||
AV_CODEC_ID_TMV,
|
||||
AV_CODEC_ID_V210,
|
||||
AV_CODEC_ID_DPX,
|
||||
AV_CODEC_ID_MAD,
|
||||
AV_CODEC_ID_FRWU,
|
||||
AV_CODEC_ID_FLASHSV2,
|
||||
AV_CODEC_ID_CDGRAPHICS,
|
||||
AV_CODEC_ID_R210,
|
||||
AV_CODEC_ID_ANM,
|
||||
AV_CODEC_ID_BINKVIDEO,
|
||||
AV_CODEC_ID_IFF_ILBM,
|
||||
#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM
|
||||
AV_CODEC_ID_KGV1,
|
||||
AV_CODEC_ID_YOP,
|
||||
AV_CODEC_ID_VP8,
|
||||
AV_CODEC_ID_PICTOR,
|
||||
AV_CODEC_ID_ANSI,
|
||||
AV_CODEC_ID_A64_MULTI,
|
||||
AV_CODEC_ID_A64_MULTI5,
|
||||
AV_CODEC_ID_R10K,
|
||||
AV_CODEC_ID_MXPEG,
|
||||
AV_CODEC_ID_LAGARITH,
|
||||
AV_CODEC_ID_PRORES,
|
||||
AV_CODEC_ID_JV,
|
||||
AV_CODEC_ID_DFA,
|
||||
AV_CODEC_ID_WMV3IMAGE,
|
||||
AV_CODEC_ID_VC1IMAGE,
|
||||
AV_CODEC_ID_UTVIDEO,
|
||||
AV_CODEC_ID_BMV_VIDEO,
|
||||
AV_CODEC_ID_VBLE,
|
||||
AV_CODEC_ID_DXTORY,
|
||||
AV_CODEC_ID_V410,
|
||||
AV_CODEC_ID_XWD,
|
||||
AV_CODEC_ID_CDXL,
|
||||
AV_CODEC_ID_XBM,
|
||||
AV_CODEC_ID_ZEROCODEC,
|
||||
AV_CODEC_ID_MSS1,
|
||||
AV_CODEC_ID_MSA1,
|
||||
AV_CODEC_ID_TSCC2,
|
||||
AV_CODEC_ID_MTS2,
|
||||
AV_CODEC_ID_CLLC,
|
||||
AV_CODEC_ID_MSS2,
|
||||
AV_CODEC_ID_VP9,
|
||||
AV_CODEC_ID_AIC,
|
||||
AV_CODEC_ID_ESCAPE130,
|
||||
AV_CODEC_ID_G2M,
|
||||
AV_CODEC_ID_WEBP,
|
||||
AV_CODEC_ID_HNM4_VIDEO,
|
||||
AV_CODEC_ID_HEVC,
|
||||
#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
|
||||
AV_CODEC_ID_FIC,
|
||||
AV_CODEC_ID_ALIAS_PIX,
|
||||
AV_CODEC_ID_BRENDER_PIX,
|
||||
AV_CODEC_ID_PAF_VIDEO,
|
||||
AV_CODEC_ID_EXR,
|
||||
AV_CODEC_ID_VP7,
|
||||
AV_CODEC_ID_SANM,
|
||||
AV_CODEC_ID_SGIRLE,
|
||||
AV_CODEC_ID_MVC1,
|
||||
AV_CODEC_ID_MVC2,
|
||||
AV_CODEC_ID_HQX,
|
||||
AV_CODEC_ID_TDSC,
|
||||
AV_CODEC_ID_HQ_HQA,
|
||||
AV_CODEC_ID_HAP,
|
||||
AV_CODEC_ID_DDS,
|
||||
AV_CODEC_ID_DXV,
|
||||
AV_CODEC_ID_SCREENPRESSO,
|
||||
AV_CODEC_ID_RSCC,
|
||||
AV_CODEC_ID_AVS2,
|
||||
AV_CODEC_ID_PGX,
|
||||
AV_CODEC_ID_AVS3,
|
||||
AV_CODEC_ID_MSP2,
|
||||
AV_CODEC_ID_VVC,
|
||||
#define AV_CODEC_ID_H266 AV_CODEC_ID_VVC
|
||||
AV_CODEC_ID_Y41P,
|
||||
AV_CODEC_ID_AVRP,
|
||||
AV_CODEC_ID_012V,
|
||||
AV_CODEC_ID_AVUI,
|
||||
AV_CODEC_ID_TARGA_Y216,
|
||||
AV_CODEC_ID_V308,
|
||||
AV_CODEC_ID_V408,
|
||||
AV_CODEC_ID_YUV4,
|
||||
AV_CODEC_ID_AVRN,
|
||||
AV_CODEC_ID_CPIA,
|
||||
AV_CODEC_ID_XFACE,
|
||||
AV_CODEC_ID_SNOW,
|
||||
AV_CODEC_ID_SMVJPEG,
|
||||
AV_CODEC_ID_APNG,
|
||||
AV_CODEC_ID_DAALA,
|
||||
AV_CODEC_ID_CFHD,
|
||||
AV_CODEC_ID_TRUEMOTION2RT,
|
||||
AV_CODEC_ID_M101,
|
||||
AV_CODEC_ID_MAGICYUV,
|
||||
AV_CODEC_ID_SHEERVIDEO,
|
||||
AV_CODEC_ID_YLC,
|
||||
AV_CODEC_ID_PSD,
|
||||
AV_CODEC_ID_PIXLET,
|
||||
AV_CODEC_ID_SPEEDHQ,
|
||||
AV_CODEC_ID_FMVC,
|
||||
AV_CODEC_ID_SCPR,
|
||||
AV_CODEC_ID_CLEARVIDEO,
|
||||
AV_CODEC_ID_XPM,
|
||||
AV_CODEC_ID_AV1,
|
||||
AV_CODEC_ID_BITPACKED,
|
||||
AV_CODEC_ID_MSCC,
|
||||
AV_CODEC_ID_SRGC,
|
||||
AV_CODEC_ID_SVG,
|
||||
AV_CODEC_ID_GDV,
|
||||
AV_CODEC_ID_FITS,
|
||||
AV_CODEC_ID_IMM4,
|
||||
AV_CODEC_ID_PROSUMER,
|
||||
AV_CODEC_ID_MWSC,
|
||||
AV_CODEC_ID_WCMV,
|
||||
AV_CODEC_ID_RASC,
|
||||
AV_CODEC_ID_HYMT,
|
||||
AV_CODEC_ID_ARBC,
|
||||
AV_CODEC_ID_AGM,
|
||||
AV_CODEC_ID_LSCR,
|
||||
AV_CODEC_ID_VP4,
|
||||
AV_CODEC_ID_IMM5,
|
||||
AV_CODEC_ID_MVDV,
|
||||
AV_CODEC_ID_MVHA,
|
||||
AV_CODEC_ID_CDTOONS,
|
||||
AV_CODEC_ID_MV30,
|
||||
AV_CODEC_ID_NOTCHLC,
|
||||
AV_CODEC_ID_PFM,
|
||||
AV_CODEC_ID_MOBICLIP,
|
||||
AV_CODEC_ID_PHOTOCD,
|
||||
AV_CODEC_ID_IPU,
|
||||
AV_CODEC_ID_ARGO,
|
||||
AV_CODEC_ID_CRI,
|
||||
AV_CODEC_ID_SIMBIOSIS_IMX,
|
||||
AV_CODEC_ID_SGA_VIDEO,
|
||||
AV_CODEC_ID_GEM,
|
||||
AV_CODEC_ID_VBN,
|
||||
AV_CODEC_ID_JPEGXL,
|
||||
AV_CODEC_ID_QOI,
|
||||
AV_CODEC_ID_PHM,
|
||||
AV_CODEC_ID_RADIANCE_HDR,
|
||||
AV_CODEC_ID_WBMP,
|
||||
AV_CODEC_ID_MEDIA100,
|
||||
AV_CODEC_ID_VQC,
|
||||
AV_CODEC_ID_PDV,
|
||||
AV_CODEC_ID_EVC,
|
||||
AV_CODEC_ID_RTV1,
|
||||
AV_CODEC_ID_VMIX,
|
||||
AV_CODEC_ID_LEAD,
|
||||
|
||||
/* various PCM "codecs" */
|
||||
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
|
||||
AV_CODEC_ID_PCM_S16LE = 0x10000,
|
||||
AV_CODEC_ID_PCM_S16BE,
|
||||
AV_CODEC_ID_PCM_U16LE,
|
||||
AV_CODEC_ID_PCM_U16BE,
|
||||
AV_CODEC_ID_PCM_S8,
|
||||
AV_CODEC_ID_PCM_U8,
|
||||
AV_CODEC_ID_PCM_MULAW,
|
||||
AV_CODEC_ID_PCM_ALAW,
|
||||
AV_CODEC_ID_PCM_S32LE,
|
||||
AV_CODEC_ID_PCM_S32BE,
|
||||
AV_CODEC_ID_PCM_U32LE,
|
||||
AV_CODEC_ID_PCM_U32BE,
|
||||
AV_CODEC_ID_PCM_S24LE,
|
||||
AV_CODEC_ID_PCM_S24BE,
|
||||
AV_CODEC_ID_PCM_U24LE,
|
||||
AV_CODEC_ID_PCM_U24BE,
|
||||
AV_CODEC_ID_PCM_S24DAUD,
|
||||
AV_CODEC_ID_PCM_ZORK,
|
||||
AV_CODEC_ID_PCM_S16LE_PLANAR,
|
||||
AV_CODEC_ID_PCM_DVD,
|
||||
AV_CODEC_ID_PCM_F32BE,
|
||||
AV_CODEC_ID_PCM_F32LE,
|
||||
AV_CODEC_ID_PCM_F64BE,
|
||||
AV_CODEC_ID_PCM_F64LE,
|
||||
AV_CODEC_ID_PCM_BLURAY,
|
||||
AV_CODEC_ID_PCM_LXF,
|
||||
AV_CODEC_ID_S302M,
|
||||
AV_CODEC_ID_PCM_S8_PLANAR,
|
||||
AV_CODEC_ID_PCM_S24LE_PLANAR,
|
||||
AV_CODEC_ID_PCM_S32LE_PLANAR,
|
||||
AV_CODEC_ID_PCM_S16BE_PLANAR,
|
||||
AV_CODEC_ID_PCM_S64LE,
|
||||
AV_CODEC_ID_PCM_S64BE,
|
||||
AV_CODEC_ID_PCM_F16LE,
|
||||
AV_CODEC_ID_PCM_F24LE,
|
||||
AV_CODEC_ID_PCM_VIDC,
|
||||
AV_CODEC_ID_PCM_SGA,
|
||||
|
||||
/* various ADPCM codecs */
|
||||
AV_CODEC_ID_ADPCM_IMA_QT = 0x11000,
|
||||
AV_CODEC_ID_ADPCM_IMA_WAV,
|
||||
AV_CODEC_ID_ADPCM_IMA_DK3,
|
||||
AV_CODEC_ID_ADPCM_IMA_DK4,
|
||||
AV_CODEC_ID_ADPCM_IMA_WS,
|
||||
AV_CODEC_ID_ADPCM_IMA_SMJPEG,
|
||||
AV_CODEC_ID_ADPCM_MS,
|
||||
AV_CODEC_ID_ADPCM_4XM,
|
||||
AV_CODEC_ID_ADPCM_XA,
|
||||
AV_CODEC_ID_ADPCM_ADX,
|
||||
AV_CODEC_ID_ADPCM_EA,
|
||||
AV_CODEC_ID_ADPCM_G726,
|
||||
AV_CODEC_ID_ADPCM_CT,
|
||||
AV_CODEC_ID_ADPCM_SWF,
|
||||
AV_CODEC_ID_ADPCM_YAMAHA,
|
||||
AV_CODEC_ID_ADPCM_SBPRO_4,
|
||||
AV_CODEC_ID_ADPCM_SBPRO_3,
|
||||
AV_CODEC_ID_ADPCM_SBPRO_2,
|
||||
AV_CODEC_ID_ADPCM_THP,
|
||||
AV_CODEC_ID_ADPCM_IMA_AMV,
|
||||
AV_CODEC_ID_ADPCM_EA_R1,
|
||||
AV_CODEC_ID_ADPCM_EA_R3,
|
||||
AV_CODEC_ID_ADPCM_EA_R2,
|
||||
AV_CODEC_ID_ADPCM_IMA_EA_SEAD,
|
||||
AV_CODEC_ID_ADPCM_IMA_EA_EACS,
|
||||
AV_CODEC_ID_ADPCM_EA_XAS,
|
||||
AV_CODEC_ID_ADPCM_EA_MAXIS_XA,
|
||||
AV_CODEC_ID_ADPCM_IMA_ISS,
|
||||
AV_CODEC_ID_ADPCM_G722,
|
||||
AV_CODEC_ID_ADPCM_IMA_APC,
|
||||
AV_CODEC_ID_ADPCM_VIMA,
|
||||
AV_CODEC_ID_ADPCM_AFC,
|
||||
AV_CODEC_ID_ADPCM_IMA_OKI,
|
||||
AV_CODEC_ID_ADPCM_DTK,
|
||||
AV_CODEC_ID_ADPCM_IMA_RAD,
|
||||
AV_CODEC_ID_ADPCM_G726LE,
|
||||
AV_CODEC_ID_ADPCM_THP_LE,
|
||||
AV_CODEC_ID_ADPCM_PSX,
|
||||
AV_CODEC_ID_ADPCM_AICA,
|
||||
AV_CODEC_ID_ADPCM_IMA_DAT4,
|
||||
AV_CODEC_ID_ADPCM_MTAF,
|
||||
AV_CODEC_ID_ADPCM_AGM,
|
||||
AV_CODEC_ID_ADPCM_ARGO,
|
||||
AV_CODEC_ID_ADPCM_IMA_SSI,
|
||||
AV_CODEC_ID_ADPCM_ZORK,
|
||||
AV_CODEC_ID_ADPCM_IMA_APM,
|
||||
AV_CODEC_ID_ADPCM_IMA_ALP,
|
||||
AV_CODEC_ID_ADPCM_IMA_MTF,
|
||||
AV_CODEC_ID_ADPCM_IMA_CUNNING,
|
||||
AV_CODEC_ID_ADPCM_IMA_MOFLEX,
|
||||
AV_CODEC_ID_ADPCM_IMA_ACORN,
|
||||
AV_CODEC_ID_ADPCM_XMD,
|
||||
|
||||
/* AMR */
|
||||
AV_CODEC_ID_AMR_NB = 0x12000,
|
||||
AV_CODEC_ID_AMR_WB,
|
||||
|
||||
/* RealAudio codecs*/
|
||||
AV_CODEC_ID_RA_144 = 0x13000,
|
||||
AV_CODEC_ID_RA_288,
|
||||
|
||||
/* various DPCM codecs */
|
||||
AV_CODEC_ID_ROQ_DPCM = 0x14000,
|
||||
AV_CODEC_ID_INTERPLAY_DPCM,
|
||||
AV_CODEC_ID_XAN_DPCM,
|
||||
AV_CODEC_ID_SOL_DPCM,
|
||||
AV_CODEC_ID_SDX2_DPCM,
|
||||
AV_CODEC_ID_GREMLIN_DPCM,
|
||||
AV_CODEC_ID_DERF_DPCM,
|
||||
AV_CODEC_ID_WADY_DPCM,
|
||||
AV_CODEC_ID_CBD2_DPCM,
|
||||
|
||||
/* audio codecs */
|
||||
AV_CODEC_ID_MP2 = 0x15000,
|
||||
AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3
|
||||
AV_CODEC_ID_AAC,
|
||||
AV_CODEC_ID_AC3,
|
||||
AV_CODEC_ID_DTS,
|
||||
AV_CODEC_ID_VORBIS,
|
||||
AV_CODEC_ID_DVAUDIO,
|
||||
AV_CODEC_ID_WMAV1,
|
||||
AV_CODEC_ID_WMAV2,
|
||||
AV_CODEC_ID_MACE3,
|
||||
AV_CODEC_ID_MACE6,
|
||||
AV_CODEC_ID_VMDAUDIO,
|
||||
AV_CODEC_ID_FLAC,
|
||||
AV_CODEC_ID_MP3ADU,
|
||||
AV_CODEC_ID_MP3ON4,
|
||||
AV_CODEC_ID_SHORTEN,
|
||||
AV_CODEC_ID_ALAC,
|
||||
AV_CODEC_ID_WESTWOOD_SND1,
|
||||
AV_CODEC_ID_GSM, ///< as in Berlin toast format
|
||||
AV_CODEC_ID_QDM2,
|
||||
AV_CODEC_ID_COOK,
|
||||
AV_CODEC_ID_TRUESPEECH,
|
||||
AV_CODEC_ID_TTA,
|
||||
AV_CODEC_ID_SMACKAUDIO,
|
||||
AV_CODEC_ID_QCELP,
|
||||
AV_CODEC_ID_WAVPACK,
|
||||
AV_CODEC_ID_DSICINAUDIO,
|
||||
AV_CODEC_ID_IMC,
|
||||
AV_CODEC_ID_MUSEPACK7,
|
||||
AV_CODEC_ID_MLP,
|
||||
AV_CODEC_ID_GSM_MS, /* as found in WAV */
|
||||
AV_CODEC_ID_ATRAC3,
|
||||
AV_CODEC_ID_APE,
|
||||
AV_CODEC_ID_NELLYMOSER,
|
||||
AV_CODEC_ID_MUSEPACK8,
|
||||
AV_CODEC_ID_SPEEX,
|
||||
AV_CODEC_ID_WMAVOICE,
|
||||
AV_CODEC_ID_WMAPRO,
|
||||
AV_CODEC_ID_WMALOSSLESS,
|
||||
AV_CODEC_ID_ATRAC3P,
|
||||
AV_CODEC_ID_EAC3,
|
||||
AV_CODEC_ID_SIPR,
|
||||
AV_CODEC_ID_MP1,
|
||||
AV_CODEC_ID_TWINVQ,
|
||||
AV_CODEC_ID_TRUEHD,
|
||||
AV_CODEC_ID_MP4ALS,
|
||||
AV_CODEC_ID_ATRAC1,
|
||||
AV_CODEC_ID_BINKAUDIO_RDFT,
|
||||
AV_CODEC_ID_BINKAUDIO_DCT,
|
||||
AV_CODEC_ID_AAC_LATM,
|
||||
AV_CODEC_ID_QDMC,
|
||||
AV_CODEC_ID_CELT,
|
||||
AV_CODEC_ID_G723_1,
|
||||
AV_CODEC_ID_G729,
|
||||
AV_CODEC_ID_8SVX_EXP,
|
||||
AV_CODEC_ID_8SVX_FIB,
|
||||
AV_CODEC_ID_BMV_AUDIO,
|
||||
AV_CODEC_ID_RALF,
|
||||
AV_CODEC_ID_IAC,
|
||||
AV_CODEC_ID_ILBC,
|
||||
AV_CODEC_ID_OPUS,
|
||||
AV_CODEC_ID_COMFORT_NOISE,
|
||||
AV_CODEC_ID_TAK,
|
||||
AV_CODEC_ID_METASOUND,
|
||||
AV_CODEC_ID_PAF_AUDIO,
|
||||
AV_CODEC_ID_ON2AVC,
|
||||
AV_CODEC_ID_DSS_SP,
|
||||
AV_CODEC_ID_CODEC2,
|
||||
AV_CODEC_ID_FFWAVESYNTH,
|
||||
AV_CODEC_ID_SONIC,
|
||||
AV_CODEC_ID_SONIC_LS,
|
||||
AV_CODEC_ID_EVRC,
|
||||
AV_CODEC_ID_SMV,
|
||||
AV_CODEC_ID_DSD_LSBF,
|
||||
AV_CODEC_ID_DSD_MSBF,
|
||||
AV_CODEC_ID_DSD_LSBF_PLANAR,
|
||||
AV_CODEC_ID_DSD_MSBF_PLANAR,
|
||||
AV_CODEC_ID_4GV,
|
||||
AV_CODEC_ID_INTERPLAY_ACM,
|
||||
AV_CODEC_ID_XMA1,
|
||||
AV_CODEC_ID_XMA2,
|
||||
AV_CODEC_ID_DST,
|
||||
AV_CODEC_ID_ATRAC3AL,
|
||||
AV_CODEC_ID_ATRAC3PAL,
|
||||
AV_CODEC_ID_DOLBY_E,
|
||||
AV_CODEC_ID_APTX,
|
||||
AV_CODEC_ID_APTX_HD,
|
||||
AV_CODEC_ID_SBC,
|
||||
AV_CODEC_ID_ATRAC9,
|
||||
AV_CODEC_ID_HCOM,
|
||||
AV_CODEC_ID_ACELP_KELVIN,
|
||||
AV_CODEC_ID_MPEGH_3D_AUDIO,
|
||||
AV_CODEC_ID_SIREN,
|
||||
AV_CODEC_ID_HCA,
|
||||
AV_CODEC_ID_FASTAUDIO,
|
||||
AV_CODEC_ID_MSNSIREN,
|
||||
AV_CODEC_ID_DFPWM,
|
||||
AV_CODEC_ID_BONK,
|
||||
AV_CODEC_ID_MISC4,
|
||||
AV_CODEC_ID_APAC,
|
||||
AV_CODEC_ID_FTR,
|
||||
AV_CODEC_ID_WAVARC,
|
||||
AV_CODEC_ID_RKA,
|
||||
AV_CODEC_ID_AC4,
|
||||
AV_CODEC_ID_OSQ,
|
||||
AV_CODEC_ID_QOA,
|
||||
AV_CODEC_ID_LC3,
|
||||
|
||||
/* subtitle codecs */
|
||||
AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
|
||||
AV_CODEC_ID_DVD_SUBTITLE = 0x17000,
|
||||
AV_CODEC_ID_DVB_SUBTITLE,
|
||||
AV_CODEC_ID_TEXT, ///< raw UTF-8 text
|
||||
AV_CODEC_ID_XSUB,
|
||||
AV_CODEC_ID_SSA,
|
||||
AV_CODEC_ID_MOV_TEXT,
|
||||
AV_CODEC_ID_HDMV_PGS_SUBTITLE,
|
||||
AV_CODEC_ID_DVB_TELETEXT,
|
||||
AV_CODEC_ID_SRT,
|
||||
AV_CODEC_ID_MICRODVD,
|
||||
AV_CODEC_ID_EIA_608,
|
||||
AV_CODEC_ID_JACOSUB,
|
||||
AV_CODEC_ID_SAMI,
|
||||
AV_CODEC_ID_REALTEXT,
|
||||
AV_CODEC_ID_STL,
|
||||
AV_CODEC_ID_SUBVIEWER1,
|
||||
AV_CODEC_ID_SUBVIEWER,
|
||||
AV_CODEC_ID_SUBRIP,
|
||||
AV_CODEC_ID_WEBVTT,
|
||||
AV_CODEC_ID_MPL2,
|
||||
AV_CODEC_ID_VPLAYER,
|
||||
AV_CODEC_ID_PJS,
|
||||
AV_CODEC_ID_ASS,
|
||||
AV_CODEC_ID_HDMV_TEXT_SUBTITLE,
|
||||
AV_CODEC_ID_TTML,
|
||||
AV_CODEC_ID_ARIB_CAPTION,
|
||||
|
||||
/* other specific kind of codecs (generally used for attachments) */
|
||||
AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
|
||||
AV_CODEC_ID_TTF = 0x18000,
|
||||
|
||||
AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream.
|
||||
AV_CODEC_ID_EPG,
|
||||
AV_CODEC_ID_BINTEXT,
|
||||
AV_CODEC_ID_XBIN,
|
||||
AV_CODEC_ID_IDF,
|
||||
AV_CODEC_ID_OTF,
|
||||
AV_CODEC_ID_SMPTE_KLV,
|
||||
AV_CODEC_ID_DVD_NAV,
|
||||
AV_CODEC_ID_TIMED_ID3,
|
||||
AV_CODEC_ID_BIN_DATA,
|
||||
AV_CODEC_ID_SMPTE_2038,
|
||||
AV_CODEC_ID_LCEVC,
|
||||
|
||||
|
||||
AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
|
||||
|
||||
AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS
|
||||
* stream (only used by libavformat) */
|
||||
AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems
|
||||
* stream (only used by libavformat) */
|
||||
AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
|
||||
AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket
|
||||
/**
|
||||
* Dummy null video codec, useful mainly for development and debugging.
|
||||
* Null encoder/decoder discard all input and never return any output.
|
||||
*/
|
||||
AV_CODEC_ID_VNULL,
|
||||
/**
|
||||
* Dummy null audio codec, useful mainly for development and debugging.
|
||||
* Null encoder/decoder discard all input and never return any output.
|
||||
*/
|
||||
AV_CODEC_ID_ANULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the type of the given codec.
|
||||
*/
|
||||
enum AVMediaType avcodec_get_type(enum AVCodecID codec_id);
|
||||
|
||||
/**
|
||||
* Get the name of a codec.
|
||||
* @return a static string identifying the codec; never NULL
|
||||
*/
|
||||
const char *avcodec_get_name(enum AVCodecID id);
|
||||
|
||||
/**
|
||||
* Return codec bits per sample.
|
||||
*
|
||||
* @param[in] codec_id the codec
|
||||
* @return Number of bits per sample or zero if unknown for the given codec.
|
||||
*/
|
||||
int av_get_bits_per_sample(enum AVCodecID codec_id);
|
||||
|
||||
/**
|
||||
* Return codec bits per sample.
|
||||
* Only return non-zero if the bits per sample is exactly correct, not an
|
||||
* approximation.
|
||||
*
|
||||
* @param[in] codec_id the codec
|
||||
* @return Number of bits per sample or zero if unknown for the given codec.
|
||||
*/
|
||||
int av_get_exact_bits_per_sample(enum AVCodecID codec_id);
|
||||
|
||||
/**
|
||||
* Return a name for the specified profile, if available.
|
||||
*
|
||||
* @param codec_id the ID of the codec to which the requested profile belongs
|
||||
* @param profile the profile value for which a name is requested
|
||||
* @return A name for the profile if found, NULL otherwise.
|
||||
*
|
||||
* @note unlike av_get_profile_name(), which searches a list of profiles
|
||||
* supported by a specific decoder or encoder implementation, this
|
||||
* function searches the list of profiles from the AVCodecDescriptor
|
||||
*/
|
||||
const char *avcodec_profile_name(enum AVCodecID codec_id, int profile);
|
||||
|
||||
/**
|
||||
* Return the PCM codec associated with a sample format.
|
||||
* @param be endianness, 0 for little, 1 for big,
|
||||
* -1 (or anything else) for native
|
||||
* @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE
|
||||
*/
|
||||
enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // AVCODEC_CODEC_ID_H
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Codec parameters public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_CODEC_PAR_H
|
||||
#define AVCODEC_CODEC_PAR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
|
||||
#include "codec_id.h"
|
||||
#include "defs.h"
|
||||
#include "packet.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavc_core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* This struct describes the properties of an encoded stream.
|
||||
*
|
||||
* sizeof(AVCodecParameters) is not a part of the public ABI, this struct must
|
||||
* be allocated with avcodec_parameters_alloc() and freed with
|
||||
* avcodec_parameters_free().
|
||||
*/
|
||||
typedef struct AVCodecParameters {
|
||||
/**
|
||||
* General type of the encoded data.
|
||||
*/
|
||||
enum AVMediaType codec_type;
|
||||
/**
|
||||
* Specific type of the encoded data (the codec used).
|
||||
*/
|
||||
enum AVCodecID codec_id;
|
||||
/**
|
||||
* Additional information about the codec (corresponds to the AVI FOURCC).
|
||||
*/
|
||||
uint32_t codec_tag;
|
||||
|
||||
/**
|
||||
* Extra binary data needed for initializing the decoder, codec-dependent.
|
||||
*
|
||||
* Must be allocated with av_malloc() and will be freed by
|
||||
* avcodec_parameters_free(). The allocated size of extradata must be at
|
||||
* least extradata_size + AV_INPUT_BUFFER_PADDING_SIZE, with the padding
|
||||
* bytes zeroed.
|
||||
*/
|
||||
uint8_t *extradata;
|
||||
/**
|
||||
* Size of the extradata content in bytes.
|
||||
*/
|
||||
int extradata_size;
|
||||
|
||||
/**
|
||||
* Additional data associated with the entire stream.
|
||||
*
|
||||
* Should be allocated with av_packet_side_data_new() or
|
||||
* av_packet_side_data_add(), and will be freed by avcodec_parameters_free().
|
||||
*/
|
||||
AVPacketSideData *coded_side_data;
|
||||
|
||||
/**
|
||||
* Amount of entries in @ref coded_side_data.
|
||||
*/
|
||||
int nb_coded_side_data;
|
||||
|
||||
/**
|
||||
* - video: the pixel format, the value corresponds to enum AVPixelFormat.
|
||||
* - audio: the sample format, the value corresponds to enum AVSampleFormat.
|
||||
*/
|
||||
int format;
|
||||
|
||||
/**
|
||||
* The average bitrate of the encoded data (in bits per second).
|
||||
*/
|
||||
int64_t bit_rate;
|
||||
|
||||
/**
|
||||
* The number of bits per sample in the codedwords.
|
||||
*
|
||||
* This is basically the bitrate per sample. It is mandatory for a bunch of
|
||||
* formats to actually decode them. It's the number of bits for one sample in
|
||||
* the actual coded bitstream.
|
||||
*
|
||||
* This could be for example 4 for ADPCM
|
||||
* For PCM formats this matches bits_per_raw_sample
|
||||
* Can be 0
|
||||
*/
|
||||
int bits_per_coded_sample;
|
||||
|
||||
/**
|
||||
* This is the number of valid bits in each output sample. If the
|
||||
* sample format has more bits, the least significant bits are additional
|
||||
* padding bits, which are always 0. Use right shifts to reduce the sample
|
||||
* to its actual size. For example, audio formats with 24 bit samples will
|
||||
* have bits_per_raw_sample set to 24, and format set to AV_SAMPLE_FMT_S32.
|
||||
* To get the original sample use "(int32_t)sample >> 8"."
|
||||
*
|
||||
* For ADPCM this might be 12 or 16 or similar
|
||||
* Can be 0
|
||||
*/
|
||||
int bits_per_raw_sample;
|
||||
|
||||
/**
|
||||
* Codec-specific bitstream restrictions that the stream conforms to.
|
||||
*/
|
||||
int profile;
|
||||
int level;
|
||||
|
||||
/**
|
||||
* Video only. The dimensions of the video frame in pixels.
|
||||
*/
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/**
|
||||
* Video only. The aspect ratio (width / height) which a single pixel
|
||||
* should have when displayed.
|
||||
*
|
||||
* When the aspect ratio is unknown / undefined, the numerator should be
|
||||
* set to 0 (the denominator may have any value).
|
||||
*/
|
||||
AVRational sample_aspect_ratio;
|
||||
|
||||
/**
|
||||
* Video only. Number of frames per second, for streams with constant frame
|
||||
* durations. Should be set to { 0, 1 } when some frames have differing
|
||||
* durations or if the value is not known.
|
||||
*
|
||||
* @note This field correponds to values that are stored in codec-level
|
||||
* headers and is typically overridden by container/transport-layer
|
||||
* timestamps, when available. It should thus be used only as a last resort,
|
||||
* when no higher-level timing information is available.
|
||||
*/
|
||||
AVRational framerate;
|
||||
|
||||
/**
|
||||
* Video only. The order of the fields in interlaced video.
|
||||
*/
|
||||
enum AVFieldOrder field_order;
|
||||
|
||||
/**
|
||||
* Video only. Additional colorspace characteristics.
|
||||
*/
|
||||
enum AVColorRange color_range;
|
||||
enum AVColorPrimaries color_primaries;
|
||||
enum AVColorTransferCharacteristic color_trc;
|
||||
enum AVColorSpace color_space;
|
||||
enum AVChromaLocation chroma_location;
|
||||
|
||||
/**
|
||||
* Video only. Number of delayed frames.
|
||||
*/
|
||||
int video_delay;
|
||||
|
||||
/**
|
||||
* Audio only. The channel layout and number of channels.
|
||||
*/
|
||||
AVChannelLayout ch_layout;
|
||||
/**
|
||||
* Audio only. The number of audio samples per second.
|
||||
*/
|
||||
int sample_rate;
|
||||
/**
|
||||
* Audio only. The number of bytes per coded audio frame, required by some
|
||||
* formats.
|
||||
*
|
||||
* Corresponds to nBlockAlign in WAVEFORMATEX.
|
||||
*/
|
||||
int block_align;
|
||||
/**
|
||||
* Audio only. Audio frame size, if known. Required by some formats to be static.
|
||||
*/
|
||||
int frame_size;
|
||||
|
||||
/**
|
||||
* Audio only. The amount of padding (in samples) inserted by the encoder at
|
||||
* the beginning of the audio. I.e. this number of leading decoded samples
|
||||
* must be discarded by the caller to get the original audio without leading
|
||||
* padding.
|
||||
*/
|
||||
int initial_padding;
|
||||
/**
|
||||
* Audio only. The amount of padding (in samples) appended by the encoder to
|
||||
* the end of the audio. I.e. this number of decoded samples must be
|
||||
* discarded by the caller from the end of the stream to get the original
|
||||
* audio without any trailing padding.
|
||||
*/
|
||||
int trailing_padding;
|
||||
/**
|
||||
* Audio only. Number of samples to skip after a discontinuity.
|
||||
*/
|
||||
int seek_preroll;
|
||||
} AVCodecParameters;
|
||||
|
||||
/**
|
||||
* Allocate a new AVCodecParameters and set its fields to default values
|
||||
* (unknown/invalid/0). The returned struct must be freed with
|
||||
* avcodec_parameters_free().
|
||||
*/
|
||||
AVCodecParameters *avcodec_parameters_alloc(void);
|
||||
|
||||
/**
|
||||
* Free an AVCodecParameters instance and everything associated with it and
|
||||
* write NULL to the supplied pointer.
|
||||
*/
|
||||
void avcodec_parameters_free(AVCodecParameters **par);
|
||||
|
||||
/**
|
||||
* Copy the contents of src to dst. Any allocated fields in dst are freed and
|
||||
* replaced with newly allocated duplicates of the corresponding fields in src.
|
||||
*
|
||||
* @return >= 0 on success, a negative AVERROR code on failure.
|
||||
*/
|
||||
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src);
|
||||
|
||||
/**
|
||||
* This function is the same as av_get_audio_frame_duration(), except it works
|
||||
* with AVCodecParameters instead of an AVCodecContext.
|
||||
*/
|
||||
int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // AVCODEC_CODEC_PAR_H
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Direct3D11 HW acceleration
|
||||
*
|
||||
* copyright (c) 2009 Laurent Aimar
|
||||
* copyright (c) 2015 Steve Lhomme
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_D3D11VA_H
|
||||
#define AVCODEC_D3D11VA_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_codec_hwaccel_d3d11va
|
||||
* Public libavcodec D3D11VA header.
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0602
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <d3d11.h>
|
||||
|
||||
/**
|
||||
* @defgroup lavc_codec_hwaccel_d3d11va Direct3D11
|
||||
* @ingroup lavc_codec_hwaccel
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* This structure is used to provides the necessary configurations and data
|
||||
* to the Direct3D11 FFmpeg HWAccel implementation.
|
||||
*
|
||||
* The application must make it available as AVCodecContext.hwaccel_context.
|
||||
*
|
||||
* Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext.
|
||||
*/
|
||||
typedef struct AVD3D11VAContext {
|
||||
/**
|
||||
* D3D11 decoder object
|
||||
*/
|
||||
ID3D11VideoDecoder *decoder;
|
||||
|
||||
/**
|
||||
* D3D11 VideoContext
|
||||
*/
|
||||
ID3D11VideoContext *video_context;
|
||||
|
||||
/**
|
||||
* D3D11 configuration used to create the decoder
|
||||
*/
|
||||
D3D11_VIDEO_DECODER_CONFIG *cfg;
|
||||
|
||||
/**
|
||||
* The number of surface in the surface array
|
||||
*/
|
||||
unsigned surface_count;
|
||||
|
||||
/**
|
||||
* The array of Direct3D surfaces used to create the decoder
|
||||
*/
|
||||
ID3D11VideoDecoderOutputView **surface;
|
||||
|
||||
/**
|
||||
* A bit field configuring the workarounds needed for using the decoder
|
||||
*/
|
||||
uint64_t workaround;
|
||||
|
||||
/**
|
||||
* Private to the FFmpeg AVHWAccel implementation
|
||||
*/
|
||||
unsigned report_id;
|
||||
|
||||
/**
|
||||
* Mutex to access video_context
|
||||
*/
|
||||
HANDLE context_mutex;
|
||||
} AVD3D11VAContext;
|
||||
|
||||
/**
|
||||
* Allocate an AVD3D11VAContext.
|
||||
*
|
||||
* @return Newly-allocated AVD3D11VAContext or NULL on failure.
|
||||
*/
|
||||
AVD3D11VAContext *av_d3d11va_alloc_context(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVCODEC_D3D11VA_H */
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_DEFS_H
|
||||
#define AVCODEC_DEFS_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup libavc
|
||||
* Misc types and constants that do not belong anywhere else.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @ingroup lavc_decoding
|
||||
* Required number of additionally allocated bytes at the end of the input bitstream for decoding.
|
||||
* This is mainly needed because some optimized bitstream readers read
|
||||
* 32 or 64 bit at once and could read over the end.<br>
|
||||
* Note: If the first 23 bits of the additional bytes are not 0, then damaged
|
||||
* MPEG bitstreams could cause overread and segfault.
|
||||
*/
|
||||
#define AV_INPUT_BUFFER_PADDING_SIZE 64
|
||||
|
||||
/**
|
||||
* Verify checksums embedded in the bitstream (could be of either encoded or
|
||||
* decoded data, depending on the format) and print an error message on mismatch.
|
||||
* If AV_EF_EXPLODE is also set, a mismatching checksum will result in the
|
||||
* decoder/demuxer returning an error.
|
||||
*/
|
||||
#define AV_EF_CRCCHECK (1<<0)
|
||||
#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations
|
||||
#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length
|
||||
#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection
|
||||
|
||||
#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue
|
||||
#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors
|
||||
#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors
|
||||
#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder/muxer should not do as an error
|
||||
|
||||
#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software.
|
||||
#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences.
|
||||
#define FF_COMPLIANCE_NORMAL 0
|
||||
#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions
|
||||
#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things.
|
||||
|
||||
|
||||
#define AV_PROFILE_UNKNOWN -99
|
||||
#define AV_PROFILE_RESERVED -100
|
||||
|
||||
#define AV_PROFILE_AAC_MAIN 0
|
||||
#define AV_PROFILE_AAC_LOW 1
|
||||
#define AV_PROFILE_AAC_SSR 2
|
||||
#define AV_PROFILE_AAC_LTP 3
|
||||
#define AV_PROFILE_AAC_HE 4
|
||||
#define AV_PROFILE_AAC_HE_V2 28
|
||||
#define AV_PROFILE_AAC_LD 22
|
||||
#define AV_PROFILE_AAC_ELD 38
|
||||
#define AV_PROFILE_AAC_USAC 41
|
||||
#define AV_PROFILE_MPEG2_AAC_LOW 128
|
||||
#define AV_PROFILE_MPEG2_AAC_HE 131
|
||||
|
||||
#define AV_PROFILE_DNXHD 0
|
||||
#define AV_PROFILE_DNXHR_LB 1
|
||||
#define AV_PROFILE_DNXHR_SQ 2
|
||||
#define AV_PROFILE_DNXHR_HQ 3
|
||||
#define AV_PROFILE_DNXHR_HQX 4
|
||||
#define AV_PROFILE_DNXHR_444 5
|
||||
|
||||
#define AV_PROFILE_DTS 20
|
||||
#define AV_PROFILE_DTS_ES 30
|
||||
#define AV_PROFILE_DTS_96_24 40
|
||||
#define AV_PROFILE_DTS_HD_HRA 50
|
||||
#define AV_PROFILE_DTS_HD_MA 60
|
||||
#define AV_PROFILE_DTS_EXPRESS 70
|
||||
#define AV_PROFILE_DTS_HD_MA_X 61
|
||||
#define AV_PROFILE_DTS_HD_MA_X_IMAX 62
|
||||
|
||||
#define AV_PROFILE_EAC3_DDP_ATMOS 30
|
||||
|
||||
#define AV_PROFILE_TRUEHD_ATMOS 30
|
||||
|
||||
#define AV_PROFILE_MPEG2_422 0
|
||||
#define AV_PROFILE_MPEG2_HIGH 1
|
||||
#define AV_PROFILE_MPEG2_SS 2
|
||||
#define AV_PROFILE_MPEG2_SNR_SCALABLE 3
|
||||
#define AV_PROFILE_MPEG2_MAIN 4
|
||||
#define AV_PROFILE_MPEG2_SIMPLE 5
|
||||
|
||||
#define AV_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag
|
||||
#define AV_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag
|
||||
|
||||
#define AV_PROFILE_H264_BASELINE 66
|
||||
#define AV_PROFILE_H264_CONSTRAINED_BASELINE (66|AV_PROFILE_H264_CONSTRAINED)
|
||||
#define AV_PROFILE_H264_MAIN 77
|
||||
#define AV_PROFILE_H264_EXTENDED 88
|
||||
#define AV_PROFILE_H264_HIGH 100
|
||||
#define AV_PROFILE_H264_HIGH_10 110
|
||||
#define AV_PROFILE_H264_HIGH_10_INTRA (110|AV_PROFILE_H264_INTRA)
|
||||
#define AV_PROFILE_H264_MULTIVIEW_HIGH 118
|
||||
#define AV_PROFILE_H264_HIGH_422 122
|
||||
#define AV_PROFILE_H264_HIGH_422_INTRA (122|AV_PROFILE_H264_INTRA)
|
||||
#define AV_PROFILE_H264_STEREO_HIGH 128
|
||||
#define AV_PROFILE_H264_HIGH_444 144
|
||||
#define AV_PROFILE_H264_HIGH_444_PREDICTIVE 244
|
||||
#define AV_PROFILE_H264_HIGH_444_INTRA (244|AV_PROFILE_H264_INTRA)
|
||||
#define AV_PROFILE_H264_CAVLC_444 44
|
||||
|
||||
#define AV_PROFILE_VC1_SIMPLE 0
|
||||
#define AV_PROFILE_VC1_MAIN 1
|
||||
#define AV_PROFILE_VC1_COMPLEX 2
|
||||
#define AV_PROFILE_VC1_ADVANCED 3
|
||||
|
||||
#define AV_PROFILE_MPEG4_SIMPLE 0
|
||||
#define AV_PROFILE_MPEG4_SIMPLE_SCALABLE 1
|
||||
#define AV_PROFILE_MPEG4_CORE 2
|
||||
#define AV_PROFILE_MPEG4_MAIN 3
|
||||
#define AV_PROFILE_MPEG4_N_BIT 4
|
||||
#define AV_PROFILE_MPEG4_SCALABLE_TEXTURE 5
|
||||
#define AV_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6
|
||||
#define AV_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7
|
||||
#define AV_PROFILE_MPEG4_HYBRID 8
|
||||
#define AV_PROFILE_MPEG4_ADVANCED_REAL_TIME 9
|
||||
#define AV_PROFILE_MPEG4_CORE_SCALABLE 10
|
||||
#define AV_PROFILE_MPEG4_ADVANCED_CODING 11
|
||||
#define AV_PROFILE_MPEG4_ADVANCED_CORE 12
|
||||
#define AV_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13
|
||||
#define AV_PROFILE_MPEG4_SIMPLE_STUDIO 14
|
||||
#define AV_PROFILE_MPEG4_ADVANCED_SIMPLE 15
|
||||
|
||||
#define AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1
|
||||
#define AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2
|
||||
#define AV_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768
|
||||
#define AV_PROFILE_JPEG2000_DCINEMA_2K 3
|
||||
#define AV_PROFILE_JPEG2000_DCINEMA_4K 4
|
||||
|
||||
#define AV_PROFILE_VP9_0 0
|
||||
#define AV_PROFILE_VP9_1 1
|
||||
#define AV_PROFILE_VP9_2 2
|
||||
#define AV_PROFILE_VP9_3 3
|
||||
|
||||
#define AV_PROFILE_HEVC_MAIN 1
|
||||
#define AV_PROFILE_HEVC_MAIN_10 2
|
||||
#define AV_PROFILE_HEVC_MAIN_STILL_PICTURE 3
|
||||
#define AV_PROFILE_HEVC_REXT 4
|
||||
#define AV_PROFILE_HEVC_MULTIVIEW_MAIN 6
|
||||
#define AV_PROFILE_HEVC_SCC 9
|
||||
|
||||
#define AV_PROFILE_VVC_MAIN_10 1
|
||||
#define AV_PROFILE_VVC_MAIN_10_444 33
|
||||
|
||||
#define AV_PROFILE_AV1_MAIN 0
|
||||
#define AV_PROFILE_AV1_HIGH 1
|
||||
#define AV_PROFILE_AV1_PROFESSIONAL 2
|
||||
|
||||
#define AV_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0
|
||||
#define AV_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1
|
||||
#define AV_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2
|
||||
#define AV_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3
|
||||
#define AV_PROFILE_MJPEG_JPEG_LS 0xf7
|
||||
|
||||
#define AV_PROFILE_SBC_MSBC 1
|
||||
|
||||
#define AV_PROFILE_PRORES_PROXY 0
|
||||
#define AV_PROFILE_PRORES_LT 1
|
||||
#define AV_PROFILE_PRORES_STANDARD 2
|
||||
#define AV_PROFILE_PRORES_HQ 3
|
||||
#define AV_PROFILE_PRORES_4444 4
|
||||
#define AV_PROFILE_PRORES_XQ 5
|
||||
|
||||
#define AV_PROFILE_ARIB_PROFILE_A 0
|
||||
#define AV_PROFILE_ARIB_PROFILE_C 1
|
||||
|
||||
#define AV_PROFILE_KLVA_SYNC 0
|
||||
#define AV_PROFILE_KLVA_ASYNC 1
|
||||
|
||||
#define AV_PROFILE_EVC_BASELINE 0
|
||||
#define AV_PROFILE_EVC_MAIN 1
|
||||
|
||||
|
||||
#define AV_LEVEL_UNKNOWN -99
|
||||
|
||||
enum AVFieldOrder {
|
||||
AV_FIELD_UNKNOWN,
|
||||
AV_FIELD_PROGRESSIVE,
|
||||
AV_FIELD_TT, ///< Top coded_first, top displayed first
|
||||
AV_FIELD_BB, ///< Bottom coded first, bottom displayed first
|
||||
AV_FIELD_TB, ///< Top coded first, bottom displayed first
|
||||
AV_FIELD_BT, ///< Bottom coded first, top displayed first
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup lavc_decoding
|
||||
*/
|
||||
enum AVDiscard{
|
||||
/* We leave some space between them for extensions (drop some
|
||||
* keyframes for intra-only or drop just some bidir frames). */
|
||||
AVDISCARD_NONE =-16, ///< discard nothing
|
||||
AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi
|
||||
AVDISCARD_NONREF = 8, ///< discard all non reference
|
||||
AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames
|
||||
AVDISCARD_NONINTRA= 24, ///< discard all non intra frames
|
||||
AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes
|
||||
AVDISCARD_ALL = 48, ///< discard all
|
||||
};
|
||||
|
||||
enum AVAudioServiceType {
|
||||
AV_AUDIO_SERVICE_TYPE_MAIN = 0,
|
||||
AV_AUDIO_SERVICE_TYPE_EFFECTS = 1,
|
||||
AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2,
|
||||
AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3,
|
||||
AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4,
|
||||
AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5,
|
||||
AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6,
|
||||
AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7,
|
||||
AV_AUDIO_SERVICE_TYPE_KARAOKE = 8,
|
||||
AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI
|
||||
};
|
||||
|
||||
/**
|
||||
* Pan Scan area.
|
||||
* This specifies the area which should be displayed.
|
||||
* Note there may be multiple such areas for one frame.
|
||||
*/
|
||||
typedef struct AVPanScan {
|
||||
/**
|
||||
* id
|
||||
* - encoding: Set by user.
|
||||
* - decoding: Set by libavcodec.
|
||||
*/
|
||||
int id;
|
||||
|
||||
/**
|
||||
* width and height in 1/16 pel
|
||||
* - encoding: Set by user.
|
||||
* - decoding: Set by libavcodec.
|
||||
*/
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/**
|
||||
* position of the top left corner in 1/16 pel for up to 3 fields/frames
|
||||
* - encoding: Set by user.
|
||||
* - decoding: Set by libavcodec.
|
||||
*/
|
||||
int16_t position[3][2];
|
||||
} AVPanScan;
|
||||
|
||||
/**
|
||||
* This structure describes the bitrate properties of an encoded bitstream. It
|
||||
* roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD
|
||||
* parameters for H.264/HEVC.
|
||||
*/
|
||||
typedef struct AVCPBProperties {
|
||||
/**
|
||||
* Maximum bitrate of the stream, in bits per second.
|
||||
* Zero if unknown or unspecified.
|
||||
*/
|
||||
int64_t max_bitrate;
|
||||
/**
|
||||
* Minimum bitrate of the stream, in bits per second.
|
||||
* Zero if unknown or unspecified.
|
||||
*/
|
||||
int64_t min_bitrate;
|
||||
/**
|
||||
* Average bitrate of the stream, in bits per second.
|
||||
* Zero if unknown or unspecified.
|
||||
*/
|
||||
int64_t avg_bitrate;
|
||||
|
||||
/**
|
||||
* The size of the buffer to which the ratecontrol is applied, in bits.
|
||||
* Zero if unknown or unspecified.
|
||||
*/
|
||||
int64_t buffer_size;
|
||||
|
||||
/**
|
||||
* The delay between the time the packet this structure is associated with
|
||||
* is received and the time when it should be decoded, in periods of a 27MHz
|
||||
* clock.
|
||||
*
|
||||
* UINT64_MAX when unknown or unspecified.
|
||||
*/
|
||||
uint64_t vbv_delay;
|
||||
} AVCPBProperties;
|
||||
|
||||
/**
|
||||
* Allocate a CPB properties structure and initialize its fields to default
|
||||
* values.
|
||||
*
|
||||
* @param size if non-NULL, the size of the allocated struct will be written
|
||||
* here. This is useful for embedding it in side data.
|
||||
*
|
||||
* @return the newly allocated struct or NULL on failure
|
||||
*/
|
||||
AVCPBProperties *av_cpb_properties_alloc(size_t *size);
|
||||
|
||||
/**
|
||||
* This structure supplies correlation between a packet timestamp and a wall clock
|
||||
* production time. The definition follows the Producer Reference Time ('prft')
|
||||
* as defined in ISO/IEC 14496-12
|
||||
*/
|
||||
typedef struct AVProducerReferenceTime {
|
||||
/**
|
||||
* A UTC timestamp, in microseconds, since Unix epoch (e.g, av_gettime()).
|
||||
*/
|
||||
int64_t wallclock;
|
||||
int flags;
|
||||
} AVProducerReferenceTime;
|
||||
|
||||
/**
|
||||
* Encode extradata length to a buffer. Used by xiph codecs.
|
||||
*
|
||||
* @param s buffer to write to; must be at least (v/255+1) bytes long
|
||||
* @param v size of extradata in bytes
|
||||
* @return number of bytes written to the buffer.
|
||||
*/
|
||||
unsigned int av_xiphlacing(unsigned char *s, unsigned int v);
|
||||
|
||||
#endif // AVCODEC_DEFS_H
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Marco Gerards <marco@gnu.org>
|
||||
* Copyright (C) 2009 David Conrad
|
||||
* Copyright (C) 2011 Jordi Ortiz
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_DIRAC_H
|
||||
#define AVCODEC_DIRAC_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Interface to Dirac Decoder/Encoder
|
||||
* @author Marco Gerards <marco@gnu.org>
|
||||
* @author David Conrad
|
||||
* @author Jordi Ortiz
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/pixfmt.h"
|
||||
#include "libavutil/rational.h"
|
||||
|
||||
/**
|
||||
* The spec limits the number of wavelet decompositions to 4 for both
|
||||
* level 1 (VC-2) and 128 (long-gop default).
|
||||
* 5 decompositions is the maximum before >16-bit buffers are needed.
|
||||
* Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting
|
||||
* the others to 4 decompositions (or 3 for the fidelity filter).
|
||||
*
|
||||
* We use this instead of MAX_DECOMPOSITIONS to save some memory.
|
||||
*/
|
||||
#define MAX_DWT_LEVELS 5
|
||||
|
||||
/**
|
||||
* Parse code values:
|
||||
*
|
||||
* Dirac Specification ->
|
||||
* 9.6.1 Table 9.1
|
||||
*
|
||||
* VC-2 Specification ->
|
||||
* 10.4.1 Table 10.1
|
||||
*/
|
||||
|
||||
enum DiracParseCodes {
|
||||
DIRAC_PCODE_SEQ_HEADER = 0x00,
|
||||
DIRAC_PCODE_END_SEQ = 0x10,
|
||||
DIRAC_PCODE_AUX = 0x20,
|
||||
DIRAC_PCODE_PAD = 0x30,
|
||||
DIRAC_PCODE_PICTURE_CODED = 0x08,
|
||||
DIRAC_PCODE_PICTURE_RAW = 0x48,
|
||||
DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8,
|
||||
DIRAC_PCODE_PICTURE_HQ = 0xE8,
|
||||
DIRAC_PCODE_INTER_NOREF_CO1 = 0x0A,
|
||||
DIRAC_PCODE_INTER_NOREF_CO2 = 0x09,
|
||||
DIRAC_PCODE_INTER_REF_CO1 = 0x0D,
|
||||
DIRAC_PCODE_INTER_REF_CO2 = 0x0E,
|
||||
DIRAC_PCODE_INTRA_REF_CO = 0x0C,
|
||||
DIRAC_PCODE_INTRA_REF_RAW = 0x4C,
|
||||
DIRAC_PCODE_INTRA_REF_PICT = 0xCC,
|
||||
DIRAC_PCODE_MAGIC = 0x42424344,
|
||||
};
|
||||
|
||||
typedef struct DiracVersionInfo {
|
||||
int major;
|
||||
int minor;
|
||||
} DiracVersionInfo;
|
||||
|
||||
typedef struct AVDiracSeqHeader {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
uint8_t chroma_format; ///< 0: 444 1: 422 2: 420
|
||||
|
||||
uint8_t interlaced;
|
||||
uint8_t top_field_first;
|
||||
|
||||
uint8_t frame_rate_index; ///< index into dirac_frame_rate[]
|
||||
uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[]
|
||||
|
||||
uint16_t clean_width;
|
||||
uint16_t clean_height;
|
||||
uint16_t clean_left_offset;
|
||||
uint16_t clean_right_offset;
|
||||
|
||||
uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[]
|
||||
uint8_t color_spec_index; ///< index into dirac_color_spec_presets[]
|
||||
|
||||
int profile;
|
||||
int level;
|
||||
|
||||
AVRational framerate;
|
||||
AVRational sample_aspect_ratio;
|
||||
|
||||
enum AVPixelFormat pix_fmt;
|
||||
enum AVColorRange color_range;
|
||||
enum AVColorPrimaries color_primaries;
|
||||
enum AVColorTransferCharacteristic color_trc;
|
||||
enum AVColorSpace colorspace;
|
||||
|
||||
DiracVersionInfo version;
|
||||
int bit_depth;
|
||||
} AVDiracSeqHeader;
|
||||
|
||||
/**
|
||||
* Parse a Dirac sequence header.
|
||||
*
|
||||
* @param dsh this function will allocate and fill an AVDiracSeqHeader struct
|
||||
* and write it into this pointer. The caller must free it with
|
||||
* av_free().
|
||||
* @param buf the data buffer
|
||||
* @param buf_size the size of the data buffer in bytes
|
||||
* @param log_ctx if non-NULL, this function will log errors here
|
||||
* @return 0 on success, a negative AVERROR code on failure
|
||||
*/
|
||||
int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh,
|
||||
const uint8_t *buf, size_t buf_size,
|
||||
void *log_ctx);
|
||||
|
||||
#endif /* AVCODEC_DIRAC_H */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_DV_PROFILE_H
|
||||
#define AVCODEC_DV_PROFILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/pixfmt.h"
|
||||
#include "libavutil/rational.h"
|
||||
|
||||
/* minimum number of bytes to read from a DV stream in order to
|
||||
* determine the profile */
|
||||
#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */
|
||||
|
||||
|
||||
/*
|
||||
* AVDVProfile is used to express the differences between various
|
||||
* DV flavors. For now it's primarily used for differentiating
|
||||
* 525/60 and 625/50, but the plans are to use it for various
|
||||
* DV specs as well (e.g. SMPTE314M vs. IEC 61834).
|
||||
*/
|
||||
typedef struct AVDVProfile {
|
||||
int dsf; /* value of the dsf in the DV header */
|
||||
int video_stype; /* stype for VAUX source pack */
|
||||
int frame_size; /* total size of one frame in bytes */
|
||||
int difseg_size; /* number of DIF segments per DIF channel */
|
||||
int n_difchan; /* number of DIF channels per frame */
|
||||
AVRational time_base; /* 1/framerate */
|
||||
int ltc_divisor; /* FPS from the LTS standpoint */
|
||||
int height; /* picture height in pixels */
|
||||
int width; /* picture width in pixels */
|
||||
AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */
|
||||
enum AVPixelFormat pix_fmt; /* picture pixel format */
|
||||
int bpm; /* blocks per macroblock */
|
||||
const uint8_t *block_sizes; /* AC block sizes, in bits */
|
||||
int audio_stride; /* size of audio_shuffle table */
|
||||
int audio_min_samples[3]; /* min amount of audio samples */
|
||||
/* for 48kHz, 44.1kHz and 32kHz */
|
||||
int audio_samples_dist[5]; /* how many samples are supposed to be */
|
||||
/* in each frame in a 5 frames window */
|
||||
const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */
|
||||
} AVDVProfile;
|
||||
|
||||
/**
|
||||
* Get a DV profile for the provided compressed frame.
|
||||
*
|
||||
* @param sys the profile used for the previous frame, may be NULL
|
||||
* @param frame the compressed data buffer
|
||||
* @param buf_size size of the buffer in bytes
|
||||
* @return the DV profile for the supplied data or NULL on failure
|
||||
*/
|
||||
const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
|
||||
const uint8_t *frame, unsigned buf_size);
|
||||
|
||||
/**
|
||||
* Get a DV profile for the provided stream parameters.
|
||||
*/
|
||||
const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt);
|
||||
|
||||
/**
|
||||
* Get a DV profile for the provided stream parameters.
|
||||
* The frame rate is used as a best-effort parameter.
|
||||
*/
|
||||
const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate);
|
||||
|
||||
#endif /* AVCODEC_DV_PROFILE_H */
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* DXVA2 HW acceleration
|
||||
*
|
||||
* copyright (c) 2009 Laurent Aimar
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_DXVA2_H
|
||||
#define AVCODEC_DXVA2_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_codec_hwaccel_dxva2
|
||||
* Public libavcodec DXVA2 header.
|
||||
*/
|
||||
|
||||
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0602
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <d3d9.h>
|
||||
#include <dxva2api.h>
|
||||
|
||||
/**
|
||||
* @defgroup lavc_codec_hwaccel_dxva2 DXVA2
|
||||
* @ingroup lavc_codec_hwaccel
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* This structure is used to provides the necessary configurations and data
|
||||
* to the DXVA2 FFmpeg HWAccel implementation.
|
||||
*
|
||||
* The application must make it available as AVCodecContext.hwaccel_context.
|
||||
*/
|
||||
struct dxva_context {
|
||||
/**
|
||||
* DXVA2 decoder object
|
||||
*/
|
||||
IDirectXVideoDecoder *decoder;
|
||||
|
||||
/**
|
||||
* DXVA2 configuration used to create the decoder
|
||||
*/
|
||||
const DXVA2_ConfigPictureDecode *cfg;
|
||||
|
||||
/**
|
||||
* The number of surface in the surface array
|
||||
*/
|
||||
unsigned surface_count;
|
||||
|
||||
/**
|
||||
* The array of Direct3D surfaces used to create the decoder
|
||||
*/
|
||||
LPDIRECT3DSURFACE9 *surface;
|
||||
|
||||
/**
|
||||
* A bit field configuring the workarounds needed for using the decoder
|
||||
*/
|
||||
uint64_t workaround;
|
||||
|
||||
/**
|
||||
* Private to the FFmpeg AVHWAccel implementation
|
||||
*/
|
||||
unsigned report_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVCODEC_DXVA2_H */
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* JNI public API functions
|
||||
*
|
||||
* Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_JNI_H
|
||||
#define AVCODEC_JNI_H
|
||||
|
||||
/*
|
||||
* Manually set a Java virtual machine which will be used to retrieve the JNI
|
||||
* environment. Once a Java VM is set it cannot be changed afterwards, meaning
|
||||
* you can call multiple times av_jni_set_java_vm with the same Java VM pointer
|
||||
* however it will error out if you try to set a different Java VM.
|
||||
*
|
||||
* @param vm Java virtual machine
|
||||
* @param log_ctx context used for logging, can be NULL
|
||||
* @return 0 on success, < 0 otherwise
|
||||
*/
|
||||
int av_jni_set_java_vm(void *vm, void *log_ctx);
|
||||
|
||||
/*
|
||||
* Get the Java virtual machine which has been set with av_jni_set_java_vm.
|
||||
*
|
||||
* @param vm Java virtual machine
|
||||
* @return a pointer to the Java virtual machine
|
||||
*/
|
||||
void *av_jni_get_java_vm(void *log_ctx);
|
||||
|
||||
/*
|
||||
* Set the Android application context which will be used to retrieve the Android
|
||||
* content resolver to handle content uris.
|
||||
*
|
||||
* This function is only available on Android.
|
||||
*
|
||||
* @param app_ctx global JNI reference to the Android application context
|
||||
* @return 0 on success, < 0 otherwise
|
||||
*/
|
||||
int av_jni_set_android_app_ctx(void *app_ctx, void *log_ctx);
|
||||
|
||||
/*
|
||||
* Get the Android application context that has been set with
|
||||
* av_jni_set_android_app_ctx.
|
||||
*
|
||||
* This function is only available on Android.
|
||||
*
|
||||
* @return a pointer the the Android application context
|
||||
*/
|
||||
void *av_jni_get_android_app_ctx(void);
|
||||
|
||||
#endif /* AVCODEC_JNI_H */
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Android MediaCodec public API
|
||||
*
|
||||
* Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_MEDIACODEC_H
|
||||
#define AVCODEC_MEDIACODEC_H
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
|
||||
/**
|
||||
* This structure holds a reference to a android/view/Surface object that will
|
||||
* be used as output by the decoder.
|
||||
*
|
||||
*/
|
||||
typedef struct AVMediaCodecContext {
|
||||
|
||||
/**
|
||||
* android/view/Surface object reference.
|
||||
*/
|
||||
void *surface;
|
||||
|
||||
} AVMediaCodecContext;
|
||||
|
||||
/**
|
||||
* Allocate and initialize a MediaCodec context.
|
||||
*
|
||||
* When decoding with MediaCodec is finished, the caller must free the
|
||||
* MediaCodec context with av_mediacodec_default_free.
|
||||
*
|
||||
* @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise
|
||||
*/
|
||||
AVMediaCodecContext *av_mediacodec_alloc_context(void);
|
||||
|
||||
/**
|
||||
* Convenience function that sets up the MediaCodec context.
|
||||
*
|
||||
* @param avctx codec context
|
||||
* @param ctx MediaCodec context to initialize
|
||||
* @param surface reference to an android/view/Surface
|
||||
* @return 0 on success, < 0 otherwise
|
||||
*/
|
||||
int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface);
|
||||
|
||||
/**
|
||||
* This function must be called to free the MediaCodec context initialized with
|
||||
* av_mediacodec_default_init().
|
||||
*
|
||||
* @param avctx codec context
|
||||
*/
|
||||
void av_mediacodec_default_free(AVCodecContext *avctx);
|
||||
|
||||
/**
|
||||
* Opaque structure representing a MediaCodec buffer to render.
|
||||
*/
|
||||
typedef struct MediaCodecBuffer AVMediaCodecBuffer;
|
||||
|
||||
/**
|
||||
* Release a MediaCodec buffer and render it to the surface that is associated
|
||||
* with the decoder. This function should only be called once on a given
|
||||
* buffer, once released the underlying buffer returns to the codec, thus
|
||||
* subsequent calls to this function will have no effect.
|
||||
*
|
||||
* @param buffer the buffer to render
|
||||
* @param render 1 to release and render the buffer to the surface or 0 to
|
||||
* discard the buffer
|
||||
* @return 0 on success, < 0 otherwise
|
||||
*/
|
||||
int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render);
|
||||
|
||||
/**
|
||||
* Release a MediaCodec buffer and render it at the given time to the surface
|
||||
* that is associated with the decoder. The timestamp must be within one second
|
||||
* of the current `java/lang/System#nanoTime()` (which is implemented using
|
||||
* `CLOCK_MONOTONIC` on Android). See the Android MediaCodec documentation
|
||||
* of [`android/media/MediaCodec#releaseOutputBuffer(int,long)`][0] for more details.
|
||||
*
|
||||
* @param buffer the buffer to render
|
||||
* @param time timestamp in nanoseconds of when to render the buffer
|
||||
* @return 0 on success, < 0 otherwise
|
||||
*
|
||||
* [0]: https://developer.android.com/reference/android/media/MediaCodec#releaseOutputBuffer(int,%20long)
|
||||
*/
|
||||
int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time);
|
||||
|
||||
#endif /* AVCODEC_MEDIACODEC_H */
|
||||
@@ -0,0 +1,887 @@
|
||||
/*
|
||||
* AVPacket public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_PACKET_H
|
||||
#define AVCODEC_PACKET_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/buffer.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#include "libavcodec/version_major.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavc_packet_side_data AVPacketSideData
|
||||
*
|
||||
* Types and functions for working with AVPacketSideData.
|
||||
* @{
|
||||
*/
|
||||
enum AVPacketSideDataType {
|
||||
/**
|
||||
* An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE
|
||||
* bytes worth of palette. This side data signals that a new palette is
|
||||
* present.
|
||||
*/
|
||||
AV_PKT_DATA_PALETTE,
|
||||
|
||||
/**
|
||||
* The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format
|
||||
* that the extradata buffer was changed and the receiving side should
|
||||
* act upon it appropriately. The new extradata is embedded in the side
|
||||
* data buffer and should be immediately used for processing the current
|
||||
* frame or packet.
|
||||
*/
|
||||
AV_PKT_DATA_NEW_EXTRADATA,
|
||||
|
||||
/**
|
||||
* An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows:
|
||||
* @code
|
||||
* u32le param_flags
|
||||
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE)
|
||||
* s32le sample_rate
|
||||
* if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS)
|
||||
* s32le width
|
||||
* s32le height
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_PARAM_CHANGE,
|
||||
|
||||
/**
|
||||
* An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of
|
||||
* structures with info about macroblocks relevant to splitting the
|
||||
* packet into smaller packets on macroblock edges (e.g. as for RFC 2190).
|
||||
* That is, it does not necessarily contain info about all macroblocks,
|
||||
* as long as the distance between macroblocks in the info is smaller
|
||||
* than the target payload size.
|
||||
* Each MB info structure is 12 bytes, and is laid out as follows:
|
||||
* @code
|
||||
* u32le bit offset from the start of the packet
|
||||
* u8 current quantizer at the start of the macroblock
|
||||
* u8 GOB number
|
||||
* u16le macroblock address within the GOB
|
||||
* u8 horizontal MV predictor
|
||||
* u8 vertical MV predictor
|
||||
* u8 horizontal MV predictor for block number 3
|
||||
* u8 vertical MV predictor for block number 3
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_H263_MB_INFO,
|
||||
|
||||
/**
|
||||
* This side data should be associated with an audio stream and contains
|
||||
* ReplayGain information in form of the AVReplayGain struct.
|
||||
*/
|
||||
AV_PKT_DATA_REPLAYGAIN,
|
||||
|
||||
/**
|
||||
* This side data contains a 3x3 transformation matrix describing an affine
|
||||
* transformation that needs to be applied to the decoded video frames for
|
||||
* correct presentation.
|
||||
*
|
||||
* See libavutil/display.h for a detailed description of the data.
|
||||
*/
|
||||
AV_PKT_DATA_DISPLAYMATRIX,
|
||||
|
||||
/**
|
||||
* This side data should be associated with a video stream and contains
|
||||
* Stereoscopic 3D information in form of the AVStereo3D struct.
|
||||
*/
|
||||
AV_PKT_DATA_STEREO3D,
|
||||
|
||||
/**
|
||||
* This side data should be associated with an audio stream and corresponds
|
||||
* to enum AVAudioServiceType.
|
||||
*/
|
||||
AV_PKT_DATA_AUDIO_SERVICE_TYPE,
|
||||
|
||||
/**
|
||||
* This side data contains quality related information from the encoder.
|
||||
* @code
|
||||
* u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad).
|
||||
* u8 picture type
|
||||
* u8 error count
|
||||
* u16 reserved
|
||||
* u64le[error count] sum of squared differences between encoder in and output
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_QUALITY_STATS,
|
||||
|
||||
/**
|
||||
* This side data contains an integer value representing the stream index
|
||||
* of a "fallback" track. A fallback track indicates an alternate
|
||||
* track to use when the current track can not be decoded for some reason.
|
||||
* e.g. no decoder available for codec.
|
||||
*/
|
||||
AV_PKT_DATA_FALLBACK_TRACK,
|
||||
|
||||
/**
|
||||
* This side data corresponds to the AVCPBProperties struct.
|
||||
*/
|
||||
AV_PKT_DATA_CPB_PROPERTIES,
|
||||
|
||||
/**
|
||||
* Recommmends skipping the specified number of samples
|
||||
* @code
|
||||
* u32le number of samples to skip from start of this packet
|
||||
* u32le number of samples to skip from end of this packet
|
||||
* u8 reason for start skip
|
||||
* u8 reason for end skip (0=padding silence, 1=convergence)
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_SKIP_SAMPLES,
|
||||
|
||||
/**
|
||||
* An AV_PKT_DATA_JP_DUALMONO side data packet indicates that
|
||||
* the packet may contain "dual mono" audio specific to Japanese DTV
|
||||
* and if it is true, recommends only the selected channel to be used.
|
||||
* @code
|
||||
* u8 selected channels (0=main/left, 1=sub/right, 2=both)
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_JP_DUALMONO,
|
||||
|
||||
/**
|
||||
* A list of zero terminated key/value strings. There is no end marker for
|
||||
* the list, so it is required to rely on the side data size to stop.
|
||||
*/
|
||||
AV_PKT_DATA_STRINGS_METADATA,
|
||||
|
||||
/**
|
||||
* Subtitle event position
|
||||
* @code
|
||||
* u32le x1
|
||||
* u32le y1
|
||||
* u32le x2
|
||||
* u32le y2
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_SUBTITLE_POSITION,
|
||||
|
||||
/**
|
||||
* Data found in BlockAdditional element of matroska container. There is
|
||||
* no end marker for the data, so it is required to rely on the side data
|
||||
* size to recognize the end. 8 byte id (as found in BlockAddId) followed
|
||||
* by data.
|
||||
*/
|
||||
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
|
||||
|
||||
/**
|
||||
* The optional first identifier line of a WebVTT cue.
|
||||
*/
|
||||
AV_PKT_DATA_WEBVTT_IDENTIFIER,
|
||||
|
||||
/**
|
||||
* The optional settings (rendering instructions) that immediately
|
||||
* follow the timestamp specifier of a WebVTT cue.
|
||||
*/
|
||||
AV_PKT_DATA_WEBVTT_SETTINGS,
|
||||
|
||||
/**
|
||||
* A list of zero terminated key/value strings. There is no end marker for
|
||||
* the list, so it is required to rely on the side data size to stop. This
|
||||
* side data includes updated metadata which appeared in the stream.
|
||||
*/
|
||||
AV_PKT_DATA_METADATA_UPDATE,
|
||||
|
||||
/**
|
||||
* MPEGTS stream ID as uint8_t, this is required to pass the stream ID
|
||||
* information from the demuxer to the corresponding muxer.
|
||||
*/
|
||||
AV_PKT_DATA_MPEGTS_STREAM_ID,
|
||||
|
||||
/**
|
||||
* Mastering display metadata (based on SMPTE-2086:2014). This metadata
|
||||
* should be associated with a video stream and contains data in the form
|
||||
* of the AVMasteringDisplayMetadata struct.
|
||||
*/
|
||||
AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
|
||||
|
||||
/**
|
||||
* This side data should be associated with a video stream and corresponds
|
||||
* to the AVSphericalMapping structure.
|
||||
*/
|
||||
AV_PKT_DATA_SPHERICAL,
|
||||
|
||||
/**
|
||||
* Content light level (based on CTA-861.3). This metadata should be
|
||||
* associated with a video stream and contains data in the form of the
|
||||
* AVContentLightMetadata struct.
|
||||
*/
|
||||
AV_PKT_DATA_CONTENT_LIGHT_LEVEL,
|
||||
|
||||
/**
|
||||
* ATSC A53 Part 4 Closed Captions. This metadata should be associated with
|
||||
* a video stream. A53 CC bitstream is stored as uint8_t in AVPacketSideData.data.
|
||||
* The number of bytes of CC data is AVPacketSideData.size.
|
||||
*/
|
||||
AV_PKT_DATA_A53_CC,
|
||||
|
||||
/**
|
||||
* This side data is encryption initialization data.
|
||||
* The format is not part of ABI, use av_encryption_init_info_* methods to
|
||||
* access.
|
||||
*/
|
||||
AV_PKT_DATA_ENCRYPTION_INIT_INFO,
|
||||
|
||||
/**
|
||||
* This side data contains encryption info for how to decrypt the packet.
|
||||
* The format is not part of ABI, use av_encryption_info_* methods to access.
|
||||
*/
|
||||
AV_PKT_DATA_ENCRYPTION_INFO,
|
||||
|
||||
/**
|
||||
* Active Format Description data consisting of a single byte as specified
|
||||
* in ETSI TS 101 154 using AVActiveFormatDescription enum.
|
||||
*/
|
||||
AV_PKT_DATA_AFD,
|
||||
|
||||
/**
|
||||
* Producer Reference Time data corresponding to the AVProducerReferenceTime struct,
|
||||
* usually exported by some encoders (on demand through the prft flag set in the
|
||||
* AVCodecContext export_side_data field).
|
||||
*/
|
||||
AV_PKT_DATA_PRFT,
|
||||
|
||||
/**
|
||||
* ICC profile data consisting of an opaque octet buffer following the
|
||||
* format described by ISO 15076-1.
|
||||
*/
|
||||
AV_PKT_DATA_ICC_PROFILE,
|
||||
|
||||
/**
|
||||
* DOVI configuration
|
||||
* ref:
|
||||
* dolby-vision-bitstreams-within-the-iso-base-media-file-format-v2.1.2, section 2.2
|
||||
* dolby-vision-bitstreams-in-mpeg-2-transport-stream-multiplex-v1.2, section 3.3
|
||||
* Tags are stored in struct AVDOVIDecoderConfigurationRecord.
|
||||
*/
|
||||
AV_PKT_DATA_DOVI_CONF,
|
||||
|
||||
/**
|
||||
* Timecode which conforms to SMPTE ST 12-1:2014. The data is an array of 4 uint32_t
|
||||
* where the first uint32_t describes how many (1-3) of the other timecodes are used.
|
||||
* The timecode format is described in the documentation of av_timecode_get_smpte_from_framenum()
|
||||
* function in libavutil/timecode.h.
|
||||
*/
|
||||
AV_PKT_DATA_S12M_TIMECODE,
|
||||
|
||||
/**
|
||||
* HDR10+ dynamic metadata associated with a video frame. The metadata is in
|
||||
* the form of the AVDynamicHDRPlus struct and contains
|
||||
* information for color volume transform - application 4 of
|
||||
* SMPTE 2094-40:2016 standard.
|
||||
*/
|
||||
AV_PKT_DATA_DYNAMIC_HDR10_PLUS,
|
||||
|
||||
/**
|
||||
* IAMF Mix Gain Parameter Data associated with the audio frame. This metadata
|
||||
* is in the form of the AVIAMFParamDefinition struct and contains information
|
||||
* defined in sections 3.6.1 and 3.8.1 of the Immersive Audio Model and
|
||||
* Formats standard.
|
||||
*/
|
||||
AV_PKT_DATA_IAMF_MIX_GAIN_PARAM,
|
||||
|
||||
/**
|
||||
* IAMF Demixing Info Parameter Data associated with the audio frame. This
|
||||
* metadata is in the form of the AVIAMFParamDefinition struct and contains
|
||||
* information defined in sections 3.6.1 and 3.8.2 of the Immersive Audio Model
|
||||
* and Formats standard.
|
||||
*/
|
||||
AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM,
|
||||
|
||||
/**
|
||||
* IAMF Recon Gain Info Parameter Data associated with the audio frame. This
|
||||
* metadata is in the form of the AVIAMFParamDefinition struct and contains
|
||||
* information defined in sections 3.6.1 and 3.8.3 of the Immersive Audio Model
|
||||
* and Formats standard.
|
||||
*/
|
||||
AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM,
|
||||
|
||||
/**
|
||||
* Ambient viewing environment metadata, as defined by H.274. This metadata
|
||||
* should be associated with a video stream and contains data in the form
|
||||
* of the AVAmbientViewingEnvironment struct.
|
||||
*/
|
||||
AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT,
|
||||
|
||||
/**
|
||||
* The number of pixels to discard from the top/bottom/left/right border of the
|
||||
* decoded frame to obtain the sub-rectangle intended for presentation.
|
||||
*
|
||||
* @code
|
||||
* u32le crop_top
|
||||
* u32le crop_bottom
|
||||
* u32le crop_left
|
||||
* u32le crop_right
|
||||
* @endcode
|
||||
*/
|
||||
AV_PKT_DATA_FRAME_CROPPING,
|
||||
|
||||
/**
|
||||
* Raw LCEVC payload data, as a uint8_t array, with NAL emulation
|
||||
* bytes intact.
|
||||
*/
|
||||
AV_PKT_DATA_LCEVC,
|
||||
|
||||
/**
|
||||
* The number of side data types.
|
||||
* This is not part of the public API/ABI in the sense that it may
|
||||
* change when new side data types are added.
|
||||
* This must stay the last enum value.
|
||||
* If its value becomes huge, some code using it
|
||||
* needs to be updated as it assumes it to be smaller than other limits.
|
||||
*/
|
||||
AV_PKT_DATA_NB
|
||||
};
|
||||
|
||||
#if FF_API_QUALITY_FACTOR
|
||||
#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure stores auxiliary information for decoding, presenting, or
|
||||
* otherwise processing the coded stream. It is typically exported by demuxers
|
||||
* and encoders and can be fed to decoders and muxers either in a per packet
|
||||
* basis, or as global side data (applying to the entire coded stream).
|
||||
*
|
||||
* Global side data is handled as follows:
|
||||
* - During demuxing, it may be exported through
|
||||
* @ref AVStream.codecpar.side_data "AVStream's codec parameters", which can
|
||||
* then be passed as input to decoders through the
|
||||
* @ref AVCodecContext.coded_side_data "decoder context's side data", for
|
||||
* initialization.
|
||||
* - For muxing, it can be fed through @ref AVStream.codecpar.side_data
|
||||
* "AVStream's codec parameters", typically the output of encoders through
|
||||
* the @ref AVCodecContext.coded_side_data "encoder context's side data", for
|
||||
* initialization.
|
||||
*
|
||||
* Packet specific side data is handled as follows:
|
||||
* - During demuxing, it may be exported through @ref AVPacket.side_data
|
||||
* "AVPacket's side data", which can then be passed as input to decoders.
|
||||
* - For muxing, it can be fed through @ref AVPacket.side_data "AVPacket's
|
||||
* side data", typically the output of encoders.
|
||||
*
|
||||
* Different modules may accept or export different types of side data
|
||||
* depending on media type and codec. Refer to @ref AVPacketSideDataType for a
|
||||
* list of defined types and where they may be found or used.
|
||||
*/
|
||||
typedef struct AVPacketSideData {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
enum AVPacketSideDataType type;
|
||||
} AVPacketSideData;
|
||||
|
||||
/**
|
||||
* Allocate a new packet side data.
|
||||
*
|
||||
* @param sd pointer to an array of side data to which the side data should
|
||||
* be added. *sd may be NULL, in which case the array will be
|
||||
* initialized.
|
||||
* @param nb_sd pointer to an integer containing the number of entries in
|
||||
* the array. The integer value will be increased by 1 on success.
|
||||
* @param type side data type
|
||||
* @param size desired side data size
|
||||
* @param flags currently unused. Must be zero
|
||||
*
|
||||
* @return pointer to freshly allocated side data on success, or NULL otherwise.
|
||||
*/
|
||||
AVPacketSideData *av_packet_side_data_new(AVPacketSideData **psd, int *pnb_sd,
|
||||
enum AVPacketSideDataType type,
|
||||
size_t size, int flags);
|
||||
|
||||
/**
|
||||
* Wrap existing data as packet side data.
|
||||
*
|
||||
* @param sd pointer to an array of side data to which the side data should
|
||||
* be added. *sd may be NULL, in which case the array will be
|
||||
* initialized
|
||||
* @param nb_sd pointer to an integer containing the number of entries in
|
||||
* the array. The integer value will be increased by 1 on success.
|
||||
* @param type side data type
|
||||
* @param data a data array. It must be allocated with the av_malloc() family
|
||||
* of functions. The ownership of the data is transferred to the
|
||||
* side data array on success
|
||||
* @param size size of the data array
|
||||
* @param flags currently unused. Must be zero
|
||||
*
|
||||
* @return pointer to freshly allocated side data on success, or NULL otherwise
|
||||
* On failure, the side data array is unchanged and the data remains
|
||||
* owned by the caller.
|
||||
*/
|
||||
AVPacketSideData *av_packet_side_data_add(AVPacketSideData **sd, int *nb_sd,
|
||||
enum AVPacketSideDataType type,
|
||||
void *data, size_t size, int flags);
|
||||
|
||||
/**
|
||||
* Get side information from a side data array.
|
||||
*
|
||||
* @param sd the array from which the side data should be fetched
|
||||
* @param nb_sd value containing the number of entries in the array.
|
||||
* @param type desired side information type
|
||||
*
|
||||
* @return pointer to side data if present or NULL otherwise
|
||||
*/
|
||||
const AVPacketSideData *av_packet_side_data_get(const AVPacketSideData *sd,
|
||||
int nb_sd,
|
||||
enum AVPacketSideDataType type);
|
||||
|
||||
/**
|
||||
* Remove side data of the given type from a side data array.
|
||||
*
|
||||
* @param sd the array from which the side data should be removed
|
||||
* @param nb_sd pointer to an integer containing the number of entries in
|
||||
* the array. Will be reduced by the amount of entries removed
|
||||
* upon return
|
||||
* @param type side information type
|
||||
*/
|
||||
void av_packet_side_data_remove(AVPacketSideData *sd, int *nb_sd,
|
||||
enum AVPacketSideDataType type);
|
||||
|
||||
/**
|
||||
* Convenience function to free all the side data stored in an array, and
|
||||
* the array itself.
|
||||
*
|
||||
* @param sd pointer to array of side data to free. Will be set to NULL
|
||||
* upon return.
|
||||
* @param nb_sd pointer to an integer containing the number of entries in
|
||||
* the array. Will be set to 0 upon return.
|
||||
*/
|
||||
void av_packet_side_data_free(AVPacketSideData **sd, int *nb_sd);
|
||||
|
||||
const char *av_packet_side_data_name(enum AVPacketSideDataType type);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lavc_packet AVPacket
|
||||
*
|
||||
* Types and functions for working with AVPacket.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* This structure stores compressed data. It is typically exported by demuxers
|
||||
* and then passed as input to decoders, or received as output from encoders and
|
||||
* then passed to muxers.
|
||||
*
|
||||
* For video, it should typically contain one compressed frame. For audio it may
|
||||
* contain several compressed frames. Encoders are allowed to output empty
|
||||
* packets, with no compressed data, containing only side data
|
||||
* (e.g. to update some stream parameters at the end of encoding).
|
||||
*
|
||||
* The semantics of data ownership depends on the buf field.
|
||||
* If it is set, the packet data is dynamically allocated and is
|
||||
* valid indefinitely until a call to av_packet_unref() reduces the
|
||||
* reference count to 0.
|
||||
*
|
||||
* If the buf field is not set av_packet_ref() would make a copy instead
|
||||
* of increasing the reference count.
|
||||
*
|
||||
* The side data is always allocated with av_malloc(), copied by
|
||||
* av_packet_ref() and freed by av_packet_unref().
|
||||
*
|
||||
* sizeof(AVPacket) being a part of the public ABI is deprecated. once
|
||||
* av_init_packet() is removed, new packets will only be able to be allocated
|
||||
* with av_packet_alloc(), and new fields may be added to the end of the struct
|
||||
* with a minor bump.
|
||||
*
|
||||
* @see av_packet_alloc
|
||||
* @see av_packet_ref
|
||||
* @see av_packet_unref
|
||||
*/
|
||||
typedef struct AVPacket {
|
||||
/**
|
||||
* A reference to the reference-counted buffer where the packet data is
|
||||
* stored.
|
||||
* May be NULL, then the packet data is not reference-counted.
|
||||
*/
|
||||
AVBufferRef *buf;
|
||||
/**
|
||||
* Presentation timestamp in AVStream->time_base units; the time at which
|
||||
* the decompressed packet will be presented to the user.
|
||||
* Can be AV_NOPTS_VALUE if it is not stored in the file.
|
||||
* pts MUST be larger or equal to dts as presentation cannot happen before
|
||||
* decompression, unless one wants to view hex dumps. Some formats misuse
|
||||
* the terms dts and pts/cts to mean something different. Such timestamps
|
||||
* must be converted to true pts/dts before they are stored in AVPacket.
|
||||
*/
|
||||
int64_t pts;
|
||||
/**
|
||||
* Decompression timestamp in AVStream->time_base units; the time at which
|
||||
* the packet is decompressed.
|
||||
* Can be AV_NOPTS_VALUE if it is not stored in the file.
|
||||
*/
|
||||
int64_t dts;
|
||||
uint8_t *data;
|
||||
int size;
|
||||
int stream_index;
|
||||
/**
|
||||
* A combination of AV_PKT_FLAG values
|
||||
*/
|
||||
int flags;
|
||||
/**
|
||||
* Additional packet data that can be provided by the container.
|
||||
* Packet can contain several types of side information.
|
||||
*/
|
||||
AVPacketSideData *side_data;
|
||||
int side_data_elems;
|
||||
|
||||
/**
|
||||
* Duration of this packet in AVStream->time_base units, 0 if unknown.
|
||||
* Equals next_pts - this_pts in presentation order.
|
||||
*/
|
||||
int64_t duration;
|
||||
|
||||
int64_t pos; ///< byte position in stream, -1 if unknown
|
||||
|
||||
/**
|
||||
* for some private data of the user
|
||||
*/
|
||||
void *opaque;
|
||||
|
||||
/**
|
||||
* AVBufferRef for free use by the API user. FFmpeg will never check the
|
||||
* contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when
|
||||
* the packet is unreferenced. av_packet_copy_props() calls create a new
|
||||
* reference with av_buffer_ref() for the target packet's opaque_ref field.
|
||||
*
|
||||
* This is unrelated to the opaque field, although it serves a similar
|
||||
* purpose.
|
||||
*/
|
||||
AVBufferRef *opaque_ref;
|
||||
|
||||
/**
|
||||
* Time base of the packet's timestamps.
|
||||
* In the future, this field may be set on packets output by encoders or
|
||||
* demuxers, but its value will be by default ignored on input to decoders
|
||||
* or muxers.
|
||||
*/
|
||||
AVRational time_base;
|
||||
} AVPacket;
|
||||
|
||||
#if FF_API_INIT_PACKET
|
||||
attribute_deprecated
|
||||
typedef struct AVPacketList {
|
||||
AVPacket pkt;
|
||||
struct AVPacketList *next;
|
||||
} AVPacketList;
|
||||
#endif
|
||||
|
||||
#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
|
||||
#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
|
||||
/**
|
||||
* Flag is used to discard packets which are required to maintain valid
|
||||
* decoder state but are not required for output and should be dropped
|
||||
* after decoding.
|
||||
**/
|
||||
#define AV_PKT_FLAG_DISCARD 0x0004
|
||||
/**
|
||||
* The packet comes from a trusted source.
|
||||
*
|
||||
* Otherwise-unsafe constructs such as arbitrary pointers to data
|
||||
* outside the packet may be followed.
|
||||
*/
|
||||
#define AV_PKT_FLAG_TRUSTED 0x0008
|
||||
/**
|
||||
* Flag is used to indicate packets that contain frames that can
|
||||
* be discarded by the decoder. I.e. Non-reference frames.
|
||||
*/
|
||||
#define AV_PKT_FLAG_DISPOSABLE 0x0010
|
||||
|
||||
enum AVSideDataParamChangeFlags {
|
||||
AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004,
|
||||
AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008,
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate an AVPacket and set its fields to default values. The resulting
|
||||
* struct must be freed using av_packet_free().
|
||||
*
|
||||
* @return An AVPacket filled with default values or NULL on failure.
|
||||
*
|
||||
* @note this only allocates the AVPacket itself, not the data buffers. Those
|
||||
* must be allocated through other means such as av_new_packet.
|
||||
*
|
||||
* @see av_new_packet
|
||||
*/
|
||||
AVPacket *av_packet_alloc(void);
|
||||
|
||||
/**
|
||||
* Create a new packet that references the same data as src.
|
||||
*
|
||||
* This is a shortcut for av_packet_alloc()+av_packet_ref().
|
||||
*
|
||||
* @return newly created AVPacket on success, NULL on error.
|
||||
*
|
||||
* @see av_packet_alloc
|
||||
* @see av_packet_ref
|
||||
*/
|
||||
AVPacket *av_packet_clone(const AVPacket *src);
|
||||
|
||||
/**
|
||||
* Free the packet, if the packet is reference counted, it will be
|
||||
* unreferenced first.
|
||||
*
|
||||
* @param pkt packet to be freed. The pointer will be set to NULL.
|
||||
* @note passing NULL is a no-op.
|
||||
*/
|
||||
void av_packet_free(AVPacket **pkt);
|
||||
|
||||
#if FF_API_INIT_PACKET
|
||||
/**
|
||||
* Initialize optional fields of a packet with default values.
|
||||
*
|
||||
* Note, this does not touch the data and size members, which have to be
|
||||
* initialized separately.
|
||||
*
|
||||
* @param pkt packet
|
||||
*
|
||||
* @see av_packet_alloc
|
||||
* @see av_packet_unref
|
||||
*
|
||||
* @deprecated This function is deprecated. Once it's removed,
|
||||
sizeof(AVPacket) will not be a part of the ABI anymore.
|
||||
*/
|
||||
attribute_deprecated
|
||||
void av_init_packet(AVPacket *pkt);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocate the payload of a packet and initialize its fields with
|
||||
* default values.
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param size wanted payload size
|
||||
* @return 0 if OK, AVERROR_xxx otherwise
|
||||
*/
|
||||
int av_new_packet(AVPacket *pkt, int size);
|
||||
|
||||
/**
|
||||
* Reduce packet size, correctly zeroing padding
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param size new size
|
||||
*/
|
||||
void av_shrink_packet(AVPacket *pkt, int size);
|
||||
|
||||
/**
|
||||
* Increase packet size, correctly zeroing padding
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param grow_by number of bytes by which to increase the size of the packet
|
||||
*/
|
||||
int av_grow_packet(AVPacket *pkt, int grow_by);
|
||||
|
||||
/**
|
||||
* Initialize a reference-counted packet from av_malloc()ed data.
|
||||
*
|
||||
* @param pkt packet to be initialized. This function will set the data, size,
|
||||
* and buf fields, all others are left untouched.
|
||||
* @param data Data allocated by av_malloc() to be used as packet data. If this
|
||||
* function returns successfully, the data is owned by the underlying AVBuffer.
|
||||
* The caller may not access the data through other means.
|
||||
* @param size size of data in bytes, without the padding. I.e. the full buffer
|
||||
* size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on error
|
||||
*/
|
||||
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
|
||||
|
||||
/**
|
||||
* Allocate new information of a packet.
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param type side information type
|
||||
* @param size side information size
|
||||
* @return pointer to fresh allocated data or NULL otherwise
|
||||
*/
|
||||
uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Wrap an existing array as a packet side data.
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param type side information type
|
||||
* @param data the side data array. It must be allocated with the av_malloc()
|
||||
* family of functions. The ownership of the data is transferred to
|
||||
* pkt.
|
||||
* @param size side information size
|
||||
* @return a non-negative number on success, a negative AVERROR code on
|
||||
* failure. On failure, the packet is unchanged and the data remains
|
||||
* owned by the caller.
|
||||
*/
|
||||
int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
||||
uint8_t *data, size_t size);
|
||||
|
||||
/**
|
||||
* Shrink the already allocated side data buffer
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param type side information type
|
||||
* @param size new side information size
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Get side information from packet.
|
||||
*
|
||||
* @param pkt packet
|
||||
* @param type desired side information type
|
||||
* @param size If supplied, *size will be set to the size of the side data
|
||||
* or to zero if the desired side data is not present.
|
||||
* @return pointer to data if present or NULL otherwise
|
||||
*/
|
||||
uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,
|
||||
size_t *size);
|
||||
|
||||
/**
|
||||
* Pack a dictionary for use in side_data.
|
||||
*
|
||||
* @param dict The dictionary to pack.
|
||||
* @param size pointer to store the size of the returned data
|
||||
* @return pointer to data if successful, NULL otherwise
|
||||
*/
|
||||
uint8_t *av_packet_pack_dictionary(AVDictionary *dict, size_t *size);
|
||||
/**
|
||||
* Unpack a dictionary from side_data.
|
||||
*
|
||||
* @param data data from side_data
|
||||
* @param size size of the data
|
||||
* @param dict the metadata storage dictionary
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int av_packet_unpack_dictionary(const uint8_t *data, size_t size,
|
||||
AVDictionary **dict);
|
||||
|
||||
/**
|
||||
* Convenience function to free all the side data stored.
|
||||
* All the other fields stay untouched.
|
||||
*
|
||||
* @param pkt packet
|
||||
*/
|
||||
void av_packet_free_side_data(AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Setup a new reference to the data described by a given packet
|
||||
*
|
||||
* If src is reference-counted, setup dst as a new reference to the
|
||||
* buffer in src. Otherwise allocate a new buffer in dst and copy the
|
||||
* data from src into it.
|
||||
*
|
||||
* All the other fields are copied from src.
|
||||
*
|
||||
* @see av_packet_unref
|
||||
*
|
||||
* @param dst Destination packet. Will be completely overwritten.
|
||||
* @param src Source packet
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on error. On error, dst
|
||||
* will be blank (as if returned by av_packet_alloc()).
|
||||
*/
|
||||
int av_packet_ref(AVPacket *dst, const AVPacket *src);
|
||||
|
||||
/**
|
||||
* Wipe the packet.
|
||||
*
|
||||
* Unreference the buffer referenced by the packet and reset the
|
||||
* remaining packet fields to their default values.
|
||||
*
|
||||
* @param pkt The packet to be unreferenced.
|
||||
*/
|
||||
void av_packet_unref(AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Move every field in src to dst and reset src.
|
||||
*
|
||||
* @see av_packet_unref
|
||||
*
|
||||
* @param src Source packet, will be reset
|
||||
* @param dst Destination packet
|
||||
*/
|
||||
void av_packet_move_ref(AVPacket *dst, AVPacket *src);
|
||||
|
||||
/**
|
||||
* Copy only "properties" fields from src to dst.
|
||||
*
|
||||
* Properties for the purpose of this function are all the fields
|
||||
* beside those related to the packet data (buf, data, size)
|
||||
*
|
||||
* @param dst Destination packet
|
||||
* @param src Source packet
|
||||
*
|
||||
* @return 0 on success AVERROR on failure.
|
||||
*/
|
||||
int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
|
||||
|
||||
/**
|
||||
* Ensure the data described by a given packet is reference counted.
|
||||
*
|
||||
* @note This function does not ensure that the reference will be writable.
|
||||
* Use av_packet_make_writable instead for that purpose.
|
||||
*
|
||||
* @see av_packet_ref
|
||||
* @see av_packet_make_writable
|
||||
*
|
||||
* @param pkt packet whose data should be made reference counted.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on error. On failure, the
|
||||
* packet is unchanged.
|
||||
*/
|
||||
int av_packet_make_refcounted(AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Create a writable reference for the data described by a given packet,
|
||||
* avoiding data copy if possible.
|
||||
*
|
||||
* @param pkt Packet whose data should be made writable.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on failure. On failure, the
|
||||
* packet is unchanged.
|
||||
*/
|
||||
int av_packet_make_writable(AVPacket *pkt);
|
||||
|
||||
/**
|
||||
* Convert valid timing fields (timestamps / durations) in a packet from one
|
||||
* timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
|
||||
* ignored.
|
||||
*
|
||||
* @param pkt packet on which the conversion will be performed
|
||||
* @param tb_src source timebase, in which the timing fields in pkt are
|
||||
* expressed
|
||||
* @param tb_dst destination timebase, to which the timing fields will be
|
||||
* converted
|
||||
*/
|
||||
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // AVCODEC_PACKET_H
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Intel MediaSDK QSV public API
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_QSV_H
|
||||
#define AVCODEC_QSV_H
|
||||
|
||||
#include <mfxvideo.h>
|
||||
|
||||
#include "libavutil/buffer.h"
|
||||
|
||||
/**
|
||||
* This struct is used for communicating QSV parameters between libavcodec and
|
||||
* the caller. It is managed by the caller and must be assigned to
|
||||
* AVCodecContext.hwaccel_context.
|
||||
* - decoding: hwaccel_context must be set on return from the get_format()
|
||||
* callback
|
||||
* - encoding: hwaccel_context must be set before avcodec_open2()
|
||||
*/
|
||||
typedef struct AVQSVContext {
|
||||
/**
|
||||
* If non-NULL, the session to use for encoding or decoding.
|
||||
* Otherwise, libavcodec will try to create an internal session.
|
||||
*/
|
||||
mfxSession session;
|
||||
|
||||
/**
|
||||
* The IO pattern to use.
|
||||
*/
|
||||
int iopattern;
|
||||
|
||||
/**
|
||||
* Extra buffers to pass to encoder or decoder initialization.
|
||||
*/
|
||||
mfxExtBuffer **ext_buffers;
|
||||
int nb_ext_buffers;
|
||||
|
||||
/**
|
||||
* Encoding only. If this field is set to non-zero by the caller, libavcodec
|
||||
* will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to
|
||||
* the encoder initialization. This only makes sense if iopattern is also
|
||||
* set to MFX_IOPATTERN_IN_OPAQUE_MEMORY.
|
||||
*
|
||||
* The number of allocated opaque surfaces will be the sum of the number
|
||||
* required by the encoder and the user-provided value nb_opaque_surfaces.
|
||||
* The array of the opaque surfaces will be exported to the caller through
|
||||
* the opaque_surfaces field.
|
||||
*
|
||||
* The caller must set this field to zero for oneVPL (MFX_VERSION >= 2.0)
|
||||
*/
|
||||
int opaque_alloc;
|
||||
|
||||
/**
|
||||
* Encoding only, and only if opaque_alloc is set to non-zero. Before
|
||||
* calling avcodec_open2(), the caller should set this field to the number
|
||||
* of extra opaque surfaces to allocate beyond what is required by the
|
||||
* encoder.
|
||||
*
|
||||
* On return from avcodec_open2(), this field will be set by libavcodec to
|
||||
* the total number of allocated opaque surfaces.
|
||||
*/
|
||||
int nb_opaque_surfaces;
|
||||
|
||||
/**
|
||||
* Encoding only, and only if opaque_alloc is set to non-zero. On return
|
||||
* from avcodec_open2(), this field will be used by libavcodec to export the
|
||||
* array of the allocated opaque surfaces to the caller, so they can be
|
||||
* passed to other parts of the pipeline.
|
||||
*
|
||||
* The buffer reference exported here is owned and managed by libavcodec,
|
||||
* the callers should make their own reference with av_buffer_ref() and free
|
||||
* it with av_buffer_unref() when it is no longer needed.
|
||||
*
|
||||
* The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1.
|
||||
*/
|
||||
AVBufferRef *opaque_surfaces;
|
||||
|
||||
/**
|
||||
* Encoding only, and only if opaque_alloc is set to non-zero. On return
|
||||
* from avcodec_open2(), this field will be set to the surface type used in
|
||||
* the opaque allocation request.
|
||||
*/
|
||||
int opaque_alloc_type;
|
||||
} AVQSVContext;
|
||||
|
||||
/**
|
||||
* Allocate a new context.
|
||||
*
|
||||
* It must be freed by the caller with av_free().
|
||||
*/
|
||||
AVQSVContext *av_qsv_alloc_context(void);
|
||||
|
||||
#endif /* AVCODEC_QSV_H */
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* The Video Decode and Presentation API for UNIX (VDPAU) is used for
|
||||
* hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1.
|
||||
*
|
||||
* Copyright (C) 2008 NVIDIA
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VDPAU_H
|
||||
#define AVCODEC_VDPAU_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_codec_hwaccel_vdpau
|
||||
* Public libavcodec VDPAU header.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer
|
||||
* @ingroup lavc_codec_hwaccel
|
||||
*
|
||||
* VDPAU hardware acceleration has two modules
|
||||
* - VDPAU decoding
|
||||
* - VDPAU presentation
|
||||
*
|
||||
* The VDPAU decoding module parses all headers using FFmpeg
|
||||
* parsing mechanisms and uses VDPAU for the actual decoding.
|
||||
*
|
||||
* As per the current implementation, the actual decoding
|
||||
* and rendering (API calls) are done as part of the VDPAU
|
||||
* presentation (vo_vdpau.c) module.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <vdpau/vdpau.h>
|
||||
|
||||
#include "libavutil/avconfig.h"
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
#include "avcodec.h"
|
||||
|
||||
struct AVCodecContext;
|
||||
struct AVFrame;
|
||||
|
||||
typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *,
|
||||
const VdpPictureInfo *, uint32_t,
|
||||
const VdpBitstreamBuffer *);
|
||||
|
||||
/**
|
||||
* This structure is used to share data between the libavcodec library and
|
||||
* the client video application.
|
||||
* This structure will be allocated and stored in AVCodecContext.hwaccel_context
|
||||
* by av_vdpau_bind_context(). Members can be set by the user once
|
||||
* during initialization or through each AVCodecContext.get_buffer()
|
||||
* function call. In any case, they must be valid prior to calling
|
||||
* decoding functions.
|
||||
*
|
||||
* The size of this structure is not a part of the public ABI and must not
|
||||
* be used outside of libavcodec.
|
||||
*/
|
||||
typedef struct AVVDPAUContext {
|
||||
/**
|
||||
* VDPAU decoder handle
|
||||
*
|
||||
* Set by user.
|
||||
*/
|
||||
VdpDecoder decoder;
|
||||
|
||||
/**
|
||||
* VDPAU decoder render callback
|
||||
*
|
||||
* Set by the user.
|
||||
*/
|
||||
VdpDecoderRender *render;
|
||||
|
||||
AVVDPAU_Render2 render2;
|
||||
} AVVDPAUContext;
|
||||
|
||||
#if FF_API_VDPAU_ALLOC_GET_SET
|
||||
/**
|
||||
* @brief allocation function for AVVDPAUContext
|
||||
*
|
||||
* Allows extending the struct without breaking API/ABI
|
||||
* @deprecated use av_vdpau_bind_context() instead
|
||||
*/
|
||||
attribute_deprecated
|
||||
AVVDPAUContext *av_alloc_vdpaucontext(void);
|
||||
|
||||
/**
|
||||
* @deprecated render2 is public and can be accessed directly
|
||||
*/
|
||||
attribute_deprecated
|
||||
AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *);
|
||||
/**
|
||||
* @deprecated render2 is public and can be accessed directly
|
||||
*/
|
||||
attribute_deprecated
|
||||
void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Associate a VDPAU device with a codec context for hardware acceleration.
|
||||
* This function is meant to be called from the get_format() codec callback,
|
||||
* or earlier. It can also be called after avcodec_flush_buffers() to change
|
||||
* the underlying VDPAU device mid-stream (e.g. to recover from non-transparent
|
||||
* display preemption).
|
||||
*
|
||||
* @note get_format() must return AV_PIX_FMT_VDPAU if this function completes
|
||||
* successfully.
|
||||
*
|
||||
* @param avctx decoding context whose get_format() callback is invoked
|
||||
* @param device VDPAU device handle to use for hardware acceleration
|
||||
* @param get_proc_address VDPAU device driver
|
||||
* @param flags zero of more OR'd AV_HWACCEL_FLAG_* flags
|
||||
*
|
||||
* @return 0 on success, an AVERROR code on failure.
|
||||
*/
|
||||
int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device,
|
||||
VdpGetProcAddress *get_proc_address, unsigned flags);
|
||||
|
||||
/**
|
||||
* Gets the parameters to create an adequate VDPAU video surface for the codec
|
||||
* context using VDPAU hardware decoding acceleration.
|
||||
*
|
||||
* @note Behavior is undefined if the context was not successfully bound to a
|
||||
* VDPAU device using av_vdpau_bind_context().
|
||||
*
|
||||
* @param avctx the codec context being used for decoding the stream
|
||||
* @param type storage space for the VDPAU video surface chroma type
|
||||
* (or NULL to ignore)
|
||||
* @param width storage space for the VDPAU video surface pixel width
|
||||
* (or NULL to ignore)
|
||||
* @param height storage space for the VDPAU video surface pixel height
|
||||
* (or NULL to ignore)
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR code on failure.
|
||||
*/
|
||||
int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type,
|
||||
uint32_t *width, uint32_t *height);
|
||||
|
||||
#if FF_API_VDPAU_ALLOC_GET_SET
|
||||
/**
|
||||
* Allocate an AVVDPAUContext.
|
||||
*
|
||||
* @return Newly-allocated AVVDPAUContext or NULL on failure.
|
||||
* @deprecated use av_vdpau_bind_context() instead
|
||||
*/
|
||||
attribute_deprecated
|
||||
AVVDPAUContext *av_vdpau_alloc_context(void);
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* AVCODEC_VDPAU_H */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VERSION_H
|
||||
#define AVCODEC_VERSION_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup libavc
|
||||
* Libavcodec version macros.
|
||||
*/
|
||||
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVCODEC_VERSION_MINOR 19
|
||||
#define LIBAVCODEC_VERSION_MICRO 101
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
LIBAVCODEC_VERSION_MINOR, \
|
||||
LIBAVCODEC_VERSION_MICRO)
|
||||
#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \
|
||||
LIBAVCODEC_VERSION_MINOR, \
|
||||
LIBAVCODEC_VERSION_MICRO)
|
||||
#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT
|
||||
|
||||
#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
|
||||
|
||||
#endif /* AVCODEC_VERSION_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VERSION_MAJOR_H
|
||||
#define AVCODEC_VERSION_MAJOR_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup libavc
|
||||
* Libavcodec version macros.
|
||||
*/
|
||||
|
||||
#define LIBAVCODEC_VERSION_MAJOR 61
|
||||
|
||||
/**
|
||||
* FF_API_* defines may be placed below to indicate public API that will be
|
||||
* dropped at a future version bump. The defines themselves are not part of
|
||||
* the public API and may change, break or disappear at any time.
|
||||
*
|
||||
* @note, when bumping the major version it is recommended to manually
|
||||
* disable each FF_API_* in its own commit instead of disabling them all
|
||||
* at once through the bump. This improves the git bisect-ability of the change.
|
||||
*/
|
||||
|
||||
#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_SUBFRAMES (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_TICKS_PER_FRAME (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_DROPCHANGED (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
|
||||
#define FF_API_AVFFT (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_FF_PROFILE_LEVEL (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_AVCODEC_CLOSE (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_BUFFER_MIN_SIZE (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_VDPAU_ALLOC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
#define FF_API_QUALITY_FACTOR (LIBAVCODEC_VERSION_MAJOR < 62)
|
||||
|
||||
#endif /* AVCODEC_VERSION_MAJOR_H */
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Videotoolbox hardware acceleration
|
||||
*
|
||||
* copyright (c) 2012 Sebastien Zwickert
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VIDEOTOOLBOX_H
|
||||
#define AVCODEC_VIDEOTOOLBOX_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavc_codec_hwaccel_videotoolbox
|
||||
* Public libavcodec Videotoolbox header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lavc_codec_hwaccel_videotoolbox VideoToolbox Decoder
|
||||
* @ingroup lavc_codec_hwaccel
|
||||
*
|
||||
* Hardware accelerated decoding using VideoToolbox on Apple Platforms
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define Picture QuickdrawPicture
|
||||
#include <VideoToolbox/VideoToolbox.h>
|
||||
#undef Picture
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
|
||||
/**
|
||||
* This struct holds all the information that needs to be passed
|
||||
* between the caller and libavcodec for initializing Videotoolbox decoding.
|
||||
* Its size is not a part of the public ABI, it must be allocated with
|
||||
* av_videotoolbox_alloc_context() and freed with av_free().
|
||||
*/
|
||||
typedef struct AVVideotoolboxContext {
|
||||
/**
|
||||
* Videotoolbox decompression session object.
|
||||
*/
|
||||
VTDecompressionSessionRef session;
|
||||
|
||||
/**
|
||||
* CVPixelBuffer Format Type that Videotoolbox will use for decoded frames.
|
||||
* set by the caller. If this is set to 0, then no specific format is
|
||||
* requested from the decoder, and its native format is output.
|
||||
*/
|
||||
OSType cv_pix_fmt_type;
|
||||
|
||||
/**
|
||||
* CoreMedia Format Description that Videotoolbox will use to create the decompression session.
|
||||
*/
|
||||
CMVideoFormatDescriptionRef cm_fmt_desc;
|
||||
|
||||
/**
|
||||
* CoreMedia codec type that Videotoolbox will use to create the decompression session.
|
||||
*/
|
||||
int cm_codec_type;
|
||||
} AVVideotoolboxContext;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVCODEC_VIDEOTOOLBOX_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* A public API for Vorbis parsing
|
||||
*
|
||||
* Determines the duration for each packet.
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VORBIS_PARSER_H
|
||||
#define AVCODEC_VORBIS_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct AVVorbisParseContext AVVorbisParseContext;
|
||||
|
||||
/**
|
||||
* Allocate and initialize the Vorbis parser using headers in the extradata.
|
||||
*/
|
||||
AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata,
|
||||
int extradata_size);
|
||||
|
||||
/**
|
||||
* Free the parser and everything associated with it.
|
||||
*/
|
||||
void av_vorbis_parse_free(AVVorbisParseContext **s);
|
||||
|
||||
#define VORBIS_FLAG_HEADER 0x00000001
|
||||
#define VORBIS_FLAG_COMMENT 0x00000002
|
||||
#define VORBIS_FLAG_SETUP 0x00000004
|
||||
|
||||
/**
|
||||
* Get the duration for a Vorbis packet.
|
||||
*
|
||||
* If @p flags is @c NULL,
|
||||
* special frames are considered invalid.
|
||||
*
|
||||
* @param s Vorbis parser context
|
||||
* @param buf buffer containing a Vorbis frame
|
||||
* @param buf_size size of the buffer
|
||||
* @param flags flags for special frames
|
||||
*/
|
||||
int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf,
|
||||
int buf_size, int *flags);
|
||||
|
||||
/**
|
||||
* Get the duration for a Vorbis packet.
|
||||
*
|
||||
* @param s Vorbis parser context
|
||||
* @param buf buffer containing a Vorbis frame
|
||||
* @param buf_size size of the buffer
|
||||
*/
|
||||
int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
|
||||
int buf_size);
|
||||
|
||||
void av_vorbis_parse_reset(AVVorbisParseContext *s);
|
||||
|
||||
#endif /* AVCODEC_VORBIS_PARSER_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_BUFFERSINK_H
|
||||
#define AVFILTER_BUFFERSINK_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavfi_buffersink
|
||||
* memory buffer sink API for audio and video
|
||||
*/
|
||||
|
||||
#include "avfilter.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavfi_buffersink Buffer sink API
|
||||
* @ingroup lavfi
|
||||
* @{
|
||||
*
|
||||
* The buffersink and abuffersink filters are there to connect filter graphs
|
||||
* to applications. They have a single input, connected to the graph, and no
|
||||
* output. Frames must be extracted using av_buffersink_get_frame() or
|
||||
* av_buffersink_get_samples().
|
||||
*
|
||||
* The format negotiated by the graph during configuration can be obtained
|
||||
* using the accessor functions:
|
||||
* - av_buffersink_get_time_base(),
|
||||
* - av_buffersink_get_format(),
|
||||
* - av_buffersink_get_frame_rate(),
|
||||
* - av_buffersink_get_w(),
|
||||
* - av_buffersink_get_h(),
|
||||
* - av_buffersink_get_sample_aspect_ratio(),
|
||||
* - av_buffersink_get_channels(),
|
||||
* - av_buffersink_get_ch_layout(),
|
||||
* - av_buffersink_get_sample_rate().
|
||||
*
|
||||
* The layout returned by av_buffersink_get_ch_layout() must de uninitialized
|
||||
* by the caller.
|
||||
*
|
||||
* The format can be constrained by setting options, using av_opt_set() and
|
||||
* related functions with the AV_OPT_SEARCH_CHILDREN flag.
|
||||
* - pix_fmts (int list),
|
||||
* - color_spaces (int list),
|
||||
* - color_ranges (int list),
|
||||
* - sample_fmts (int list),
|
||||
* - sample_rates (int list),
|
||||
* - ch_layouts (string),
|
||||
* - channel_counts (int list),
|
||||
* - all_channel_counts (bool).
|
||||
* Most of these options are of type binary, and should be set using
|
||||
* av_opt_set_int_list() or av_opt_set_bin(). If they are not set, all
|
||||
* corresponding formats are accepted.
|
||||
*
|
||||
* As a special case, if ch_layouts is not set, all valid channel layouts are
|
||||
* accepted except for UNSPEC layouts, unless all_channel_counts is set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a frame with filtered data from sink and put it in frame.
|
||||
*
|
||||
* @param ctx pointer to a buffersink or abuffersink filter context.
|
||||
* @param frame pointer to an allocated frame that will be filled with data.
|
||||
* The data must be freed using av_frame_unref() / av_frame_free()
|
||||
* @param flags a combination of AV_BUFFERSINK_FLAG_* flags
|
||||
*
|
||||
* @return >= 0 in for success, a negative AVERROR code for failure.
|
||||
*/
|
||||
int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags);
|
||||
|
||||
/**
|
||||
* Tell av_buffersink_get_buffer_ref() to read video/samples buffer
|
||||
* reference, but not remove it from the buffer. This is useful if you
|
||||
* need only to read a video/samples buffer, without to fetch it.
|
||||
*/
|
||||
#define AV_BUFFERSINK_FLAG_PEEK 1
|
||||
|
||||
/**
|
||||
* Tell av_buffersink_get_buffer_ref() not to request a frame from its input.
|
||||
* If a frame is already buffered, it is read (and removed from the buffer),
|
||||
* but if no frame is present, return AVERROR(EAGAIN).
|
||||
*/
|
||||
#define AV_BUFFERSINK_FLAG_NO_REQUEST 2
|
||||
|
||||
/**
|
||||
* Set the frame size for an audio buffer sink.
|
||||
*
|
||||
* All calls to av_buffersink_get_buffer_ref will return a buffer with
|
||||
* exactly the specified number of samples, or AVERROR(EAGAIN) if there is
|
||||
* not enough. The last buffer at EOF will be padded with 0.
|
||||
*/
|
||||
void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size);
|
||||
|
||||
/**
|
||||
* @defgroup lavfi_buffersink_accessors Buffer sink accessors
|
||||
* Get the properties of the stream
|
||||
* @{
|
||||
*/
|
||||
|
||||
enum AVMediaType av_buffersink_get_type (const AVFilterContext *ctx);
|
||||
AVRational av_buffersink_get_time_base (const AVFilterContext *ctx);
|
||||
int av_buffersink_get_format (const AVFilterContext *ctx);
|
||||
|
||||
AVRational av_buffersink_get_frame_rate (const AVFilterContext *ctx);
|
||||
int av_buffersink_get_w (const AVFilterContext *ctx);
|
||||
int av_buffersink_get_h (const AVFilterContext *ctx);
|
||||
AVRational av_buffersink_get_sample_aspect_ratio (const AVFilterContext *ctx);
|
||||
enum AVColorSpace av_buffersink_get_colorspace (const AVFilterContext *ctx);
|
||||
enum AVColorRange av_buffersink_get_color_range (const AVFilterContext *ctx);
|
||||
|
||||
int av_buffersink_get_channels (const AVFilterContext *ctx);
|
||||
int av_buffersink_get_ch_layout (const AVFilterContext *ctx,
|
||||
AVChannelLayout *ch_layout);
|
||||
int av_buffersink_get_sample_rate (const AVFilterContext *ctx);
|
||||
|
||||
AVBufferRef * av_buffersink_get_hw_frames_ctx (const AVFilterContext *ctx);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Get a frame with filtered data from sink and put it in frame.
|
||||
*
|
||||
* @param ctx pointer to a context of a buffersink or abuffersink AVFilter.
|
||||
* @param frame pointer to an allocated frame that will be filled with data.
|
||||
* The data must be freed using av_frame_unref() / av_frame_free()
|
||||
*
|
||||
* @return
|
||||
* - >= 0 if a frame was successfully returned.
|
||||
* - AVERROR(EAGAIN) if no frames are available at this point; more
|
||||
* input frames must be added to the filtergraph to get more output.
|
||||
* - AVERROR_EOF if there will be no more output frames on this sink.
|
||||
* - A different negative AVERROR code in other failure cases.
|
||||
*/
|
||||
int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
|
||||
|
||||
/**
|
||||
* Same as av_buffersink_get_frame(), but with the ability to specify the number
|
||||
* of samples read. This function is less efficient than
|
||||
* av_buffersink_get_frame(), because it copies the data around.
|
||||
*
|
||||
* @param ctx pointer to a context of the abuffersink AVFilter.
|
||||
* @param frame pointer to an allocated frame that will be filled with data.
|
||||
* The data must be freed using av_frame_unref() / av_frame_free()
|
||||
* frame will contain exactly nb_samples audio samples, except at
|
||||
* the end of stream, when it can contain less than nb_samples.
|
||||
*
|
||||
* @return The return codes have the same meaning as for
|
||||
* av_buffersink_get_frame().
|
||||
*
|
||||
* @warning do not mix this function with av_buffersink_get_frame(). Use only one or
|
||||
* the other with a single sink, not both.
|
||||
*/
|
||||
int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVFILTER_BUFFERSINK_H */
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_BUFFERSRC_H
|
||||
#define AVFILTER_BUFFERSRC_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavfi_buffersrc
|
||||
* Memory buffer source API.
|
||||
*/
|
||||
|
||||
#include "avfilter.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavfi_buffersrc Buffer source API
|
||||
* @ingroup lavfi
|
||||
* @{
|
||||
*/
|
||||
|
||||
enum {
|
||||
|
||||
/**
|
||||
* Do not check for format changes.
|
||||
*/
|
||||
AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1,
|
||||
|
||||
/**
|
||||
* Immediately push the frame to the output.
|
||||
*/
|
||||
AV_BUFFERSRC_FLAG_PUSH = 4,
|
||||
|
||||
/**
|
||||
* Keep a reference to the frame.
|
||||
* If the frame if reference-counted, create a new reference; otherwise
|
||||
* copy the frame data.
|
||||
*/
|
||||
AV_BUFFERSRC_FLAG_KEEP_REF = 8,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of failed requests.
|
||||
*
|
||||
* A failed request is when the request_frame method is called while no
|
||||
* frame is present in the buffer.
|
||||
* The number is reset when a frame is added.
|
||||
*/
|
||||
unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src);
|
||||
|
||||
/**
|
||||
* This structure contains the parameters describing the frames that will be
|
||||
* passed to this filter.
|
||||
*
|
||||
* It should be allocated with av_buffersrc_parameters_alloc() and freed with
|
||||
* av_free(). All the allocated fields in it remain owned by the caller.
|
||||
*/
|
||||
typedef struct AVBufferSrcParameters {
|
||||
/**
|
||||
* video: the pixel format, value corresponds to enum AVPixelFormat
|
||||
* audio: the sample format, value corresponds to enum AVSampleFormat
|
||||
*/
|
||||
int format;
|
||||
/**
|
||||
* The timebase to be used for the timestamps on the input frames.
|
||||
*/
|
||||
AVRational time_base;
|
||||
|
||||
/**
|
||||
* Video only, the display dimensions of the input frames.
|
||||
*/
|
||||
int width, height;
|
||||
|
||||
/**
|
||||
* Video only, the sample (pixel) aspect ratio.
|
||||
*/
|
||||
AVRational sample_aspect_ratio;
|
||||
|
||||
/**
|
||||
* Video only, the frame rate of the input video. This field must only be
|
||||
* set to a non-zero value if input stream has a known constant framerate
|
||||
* and should be left at its initial value if the framerate is variable or
|
||||
* unknown.
|
||||
*/
|
||||
AVRational frame_rate;
|
||||
|
||||
/**
|
||||
* Video with a hwaccel pixel format only. This should be a reference to an
|
||||
* AVHWFramesContext instance describing the input frames.
|
||||
*/
|
||||
AVBufferRef *hw_frames_ctx;
|
||||
|
||||
/**
|
||||
* Audio only, the audio sampling rate in samples per second.
|
||||
*/
|
||||
int sample_rate;
|
||||
|
||||
/**
|
||||
* Audio only, the audio channel layout
|
||||
*/
|
||||
AVChannelLayout ch_layout;
|
||||
|
||||
/**
|
||||
* Video only, the YUV colorspace and range.
|
||||
*/
|
||||
enum AVColorSpace color_space;
|
||||
enum AVColorRange color_range;
|
||||
} AVBufferSrcParameters;
|
||||
|
||||
/**
|
||||
* Allocate a new AVBufferSrcParameters instance. It should be freed by the
|
||||
* caller with av_free().
|
||||
*/
|
||||
AVBufferSrcParameters *av_buffersrc_parameters_alloc(void);
|
||||
|
||||
/**
|
||||
* Initialize the buffersrc or abuffersrc filter with the provided parameters.
|
||||
* This function may be called multiple times, the later calls override the
|
||||
* previous ones. Some of the parameters may also be set through AVOptions, then
|
||||
* whatever method is used last takes precedence.
|
||||
*
|
||||
* @param ctx an instance of the buffersrc or abuffersrc filter
|
||||
* @param param the stream parameters. The frames later passed to this filter
|
||||
* must conform to those parameters. All the allocated fields in
|
||||
* param remain owned by the caller, libavfilter will make internal
|
||||
* copies or references when necessary.
|
||||
* @return 0 on success, a negative AVERROR code on failure.
|
||||
*/
|
||||
int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *param);
|
||||
|
||||
/**
|
||||
* Add a frame to the buffer source.
|
||||
*
|
||||
* @param ctx an instance of the buffersrc filter
|
||||
* @param frame frame to be added. If the frame is reference counted, this
|
||||
* function will make a new reference to it. Otherwise the frame data will be
|
||||
* copied.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on error
|
||||
*
|
||||
* This function is equivalent to av_buffersrc_add_frame_flags() with the
|
||||
* AV_BUFFERSRC_FLAG_KEEP_REF flag.
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame);
|
||||
|
||||
/**
|
||||
* Add a frame to the buffer source.
|
||||
*
|
||||
* @param ctx an instance of the buffersrc filter
|
||||
* @param frame frame to be added. If the frame is reference counted, this
|
||||
* function will take ownership of the reference(s) and reset the frame.
|
||||
* Otherwise the frame data will be copied. If this function returns an error,
|
||||
* the input frame is not touched.
|
||||
*
|
||||
* @return 0 on success, a negative AVERROR on error.
|
||||
*
|
||||
* @note the difference between this function and av_buffersrc_write_frame() is
|
||||
* that av_buffersrc_write_frame() creates a new reference to the input frame,
|
||||
* while this function takes ownership of the reference passed to it.
|
||||
*
|
||||
* This function is equivalent to av_buffersrc_add_frame_flags() without the
|
||||
* AV_BUFFERSRC_FLAG_KEEP_REF flag.
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
|
||||
|
||||
/**
|
||||
* Add a frame to the buffer source.
|
||||
*
|
||||
* By default, if the frame is reference-counted, this function will take
|
||||
* ownership of the reference(s) and reset the frame. This can be controlled
|
||||
* using the flags.
|
||||
*
|
||||
* If this function returns an error, the input frame is not touched.
|
||||
*
|
||||
* @param buffer_src pointer to a buffer source context
|
||||
* @param frame a frame, or NULL to mark EOF
|
||||
* @param flags a combination of AV_BUFFERSRC_FLAG_*
|
||||
* @return >= 0 in case of success, a negative AVERROR code
|
||||
* in case of failure
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src,
|
||||
AVFrame *frame, int flags);
|
||||
|
||||
/**
|
||||
* Close the buffer source after EOF.
|
||||
*
|
||||
* This is similar to passing NULL to av_buffersrc_add_frame_flags()
|
||||
* except it takes the timestamp of the EOF, i.e. the timestamp of the end
|
||||
* of the last frame.
|
||||
*/
|
||||
int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVFILTER_BUFFERSRC_H */
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Version macros.
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_VERSION_H
|
||||
#define AVFILTER_VERSION_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavfi
|
||||
* Libavfilter version macros
|
||||
*/
|
||||
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVFILTER_VERSION_MINOR 4
|
||||
#define LIBAVFILTER_VERSION_MICRO 100
|
||||
|
||||
|
||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
||||
LIBAVFILTER_VERSION_MINOR, \
|
||||
LIBAVFILTER_VERSION_MICRO)
|
||||
#define LIBAVFILTER_VERSION AV_VERSION(LIBAVFILTER_VERSION_MAJOR, \
|
||||
LIBAVFILTER_VERSION_MINOR, \
|
||||
LIBAVFILTER_VERSION_MICRO)
|
||||
#define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT
|
||||
|
||||
#define LIBAVFILTER_IDENT "Lavfi" AV_STRINGIFY(LIBAVFILTER_VERSION)
|
||||
|
||||
#endif /* AVFILTER_VERSION_H */
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Version macros.
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_VERSION_MAJOR_H
|
||||
#define AVFILTER_VERSION_MAJOR_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavfi
|
||||
* Libavfilter version macros
|
||||
*/
|
||||
|
||||
#define LIBAVFILTER_VERSION_MAJOR 10
|
||||
|
||||
/**
|
||||
* FF_API_* defines may be placed below to indicate public API that will be
|
||||
* dropped at a future version bump. The defines themselves are not part of
|
||||
* the public API and may change, break or disappear at any time.
|
||||
*/
|
||||
|
||||
#define FF_API_LINK_PUBLIC (LIBAVFILTER_VERSION_MAJOR < 11)
|
||||
|
||||
#endif /* AVFILTER_VERSION_MAJOR_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,831 @@
|
||||
/*
|
||||
* copyright (c) 2001 Fabrice Bellard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef AVFORMAT_AVIO_H
|
||||
#define AVFORMAT_AVIO_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavf_io
|
||||
* Buffered I/O operations
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/log.h"
|
||||
|
||||
#include "libavformat/version_major.h"
|
||||
|
||||
/**
|
||||
* Seeking works like for a local file.
|
||||
*/
|
||||
#define AVIO_SEEKABLE_NORMAL (1 << 0)
|
||||
|
||||
/**
|
||||
* Seeking by timestamp with avio_seek_time() is possible.
|
||||
*/
|
||||
#define AVIO_SEEKABLE_TIME (1 << 1)
|
||||
|
||||
/**
|
||||
* Callback for checking whether to abort blocking functions.
|
||||
* AVERROR_EXIT is returned in this case by the interrupted
|
||||
* function. During blocking operations, callback is called with
|
||||
* opaque as parameter. If the callback returns 1, the
|
||||
* blocking operation will be aborted.
|
||||
*
|
||||
* No members can be added to this struct without a major bump, if
|
||||
* new elements have been added after this struct in AVFormatContext
|
||||
* or AVIOContext.
|
||||
*/
|
||||
typedef struct AVIOInterruptCB {
|
||||
int (*callback)(void*);
|
||||
void *opaque;
|
||||
} AVIOInterruptCB;
|
||||
|
||||
/**
|
||||
* Directory entry types.
|
||||
*/
|
||||
enum AVIODirEntryType {
|
||||
AVIO_ENTRY_UNKNOWN,
|
||||
AVIO_ENTRY_BLOCK_DEVICE,
|
||||
AVIO_ENTRY_CHARACTER_DEVICE,
|
||||
AVIO_ENTRY_DIRECTORY,
|
||||
AVIO_ENTRY_NAMED_PIPE,
|
||||
AVIO_ENTRY_SYMBOLIC_LINK,
|
||||
AVIO_ENTRY_SOCKET,
|
||||
AVIO_ENTRY_FILE,
|
||||
AVIO_ENTRY_SERVER,
|
||||
AVIO_ENTRY_SHARE,
|
||||
AVIO_ENTRY_WORKGROUP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes single entry of the directory.
|
||||
*
|
||||
* Only name and type fields are guaranteed be set.
|
||||
* Rest of fields are protocol or/and platform dependent and might be unknown.
|
||||
*/
|
||||
typedef struct AVIODirEntry {
|
||||
char *name; /**< Filename */
|
||||
int type; /**< Type of the entry */
|
||||
int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise.
|
||||
Name can be encoded with UTF-8 even though 0 is set. */
|
||||
int64_t size; /**< File size in bytes, -1 if unknown. */
|
||||
int64_t modification_timestamp; /**< Time of last modification in microseconds since unix
|
||||
epoch, -1 if unknown. */
|
||||
int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch,
|
||||
-1 if unknown. */
|
||||
int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix
|
||||
epoch, -1 if unknown. */
|
||||
int64_t user_id; /**< User ID of owner, -1 if unknown. */
|
||||
int64_t group_id; /**< Group ID of owner, -1 if unknown. */
|
||||
int64_t filemode; /**< Unix file mode, -1 if unknown. */
|
||||
} AVIODirEntry;
|
||||
|
||||
typedef struct AVIODirContext AVIODirContext;
|
||||
|
||||
/**
|
||||
* Different data types that can be returned via the AVIO
|
||||
* write_data_type callback.
|
||||
*/
|
||||
enum AVIODataMarkerType {
|
||||
/**
|
||||
* Header data; this needs to be present for the stream to be decodeable.
|
||||
*/
|
||||
AVIO_DATA_MARKER_HEADER,
|
||||
/**
|
||||
* A point in the output bytestream where a decoder can start decoding
|
||||
* (i.e. a keyframe). A demuxer/decoder given the data flagged with
|
||||
* AVIO_DATA_MARKER_HEADER, followed by any AVIO_DATA_MARKER_SYNC_POINT,
|
||||
* should give decodeable results.
|
||||
*/
|
||||
AVIO_DATA_MARKER_SYNC_POINT,
|
||||
/**
|
||||
* A point in the output bytestream where a demuxer can start parsing
|
||||
* (for non self synchronizing bytestream formats). That is, any
|
||||
* non-keyframe packet start point.
|
||||
*/
|
||||
AVIO_DATA_MARKER_BOUNDARY_POINT,
|
||||
/**
|
||||
* This is any, unlabelled data. It can either be a muxer not marking
|
||||
* any positions at all, it can be an actual boundary/sync point
|
||||
* that the muxer chooses not to mark, or a later part of a packet/fragment
|
||||
* that is cut into multiple write callbacks due to limited IO buffer size.
|
||||
*/
|
||||
AVIO_DATA_MARKER_UNKNOWN,
|
||||
/**
|
||||
* Trailer data, which doesn't contain actual content, but only for
|
||||
* finalizing the output file.
|
||||
*/
|
||||
AVIO_DATA_MARKER_TRAILER,
|
||||
/**
|
||||
* A point in the output bytestream where the underlying AVIOContext might
|
||||
* flush the buffer depending on latency or buffering requirements. Typically
|
||||
* means the end of a packet.
|
||||
*/
|
||||
AVIO_DATA_MARKER_FLUSH_POINT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Bytestream IO Context.
|
||||
* New public fields can be added with minor version bumps.
|
||||
* Removal, reordering and changes to existing public fields require
|
||||
* a major version bump.
|
||||
* sizeof(AVIOContext) must not be used outside libav*.
|
||||
*
|
||||
* @note None of the function pointers in AVIOContext should be called
|
||||
* directly, they should only be set by the client application
|
||||
* when implementing custom I/O. Normally these are set to the
|
||||
* function pointers specified in avio_alloc_context()
|
||||
*/
|
||||
typedef struct AVIOContext {
|
||||
/**
|
||||
* A class for private options.
|
||||
*
|
||||
* If this AVIOContext is created by avio_open2(), av_class is set and
|
||||
* passes the options down to protocols.
|
||||
*
|
||||
* If this AVIOContext is manually allocated, then av_class may be set by
|
||||
* the caller.
|
||||
*
|
||||
* warning -- this field can be NULL, be sure to not pass this AVIOContext
|
||||
* to any av_opt_* functions in that case.
|
||||
*/
|
||||
const AVClass *av_class;
|
||||
|
||||
/*
|
||||
* The following shows the relationship between buffer, buf_ptr,
|
||||
* buf_ptr_max, buf_end, buf_size, and pos, when reading and when writing
|
||||
* (since AVIOContext is used for both):
|
||||
*
|
||||
**********************************************************************************
|
||||
* READING
|
||||
**********************************************************************************
|
||||
*
|
||||
* | buffer_size |
|
||||
* |---------------------------------------|
|
||||
* | |
|
||||
*
|
||||
* buffer buf_ptr buf_end
|
||||
* +---------------+-----------------------+
|
||||
* |/ / / / / / / /|/ / / / / / /| |
|
||||
* read buffer: |/ / consumed / | to be read /| |
|
||||
* |/ / / / / / / /|/ / / / / / /| |
|
||||
* +---------------+-----------------------+
|
||||
*
|
||||
* pos
|
||||
* +-------------------------------------------+-----------------+
|
||||
* input file: | | |
|
||||
* +-------------------------------------------+-----------------+
|
||||
*
|
||||
*
|
||||
**********************************************************************************
|
||||
* WRITING
|
||||
**********************************************************************************
|
||||
*
|
||||
* | buffer_size |
|
||||
* |--------------------------------------|
|
||||
* | |
|
||||
*
|
||||
* buf_ptr_max
|
||||
* buffer (buf_ptr) buf_end
|
||||
* +-----------------------+--------------+
|
||||
* |/ / / / / / / / / / / /| |
|
||||
* write buffer: | / / to be flushed / / | |
|
||||
* |/ / / / / / / / / / / /| |
|
||||
* +-----------------------+--------------+
|
||||
* buf_ptr can be in this
|
||||
* due to a backward seek
|
||||
*
|
||||
* pos
|
||||
* +-------------+----------------------------------------------+
|
||||
* output file: | | |
|
||||
* +-------------+----------------------------------------------+
|
||||
*
|
||||
*/
|
||||
unsigned char *buffer; /**< Start of the buffer. */
|
||||
int buffer_size; /**< Maximum buffer size */
|
||||
unsigned char *buf_ptr; /**< Current position in the buffer */
|
||||
unsigned char *buf_end; /**< End of the data, may be less than
|
||||
buffer+buffer_size if the read function returned
|
||||
less data than requested, e.g. for streams where
|
||||
no more data has been received yet. */
|
||||
void *opaque; /**< A private pointer, passed to the read/write/seek/...
|
||||
functions. */
|
||||
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
|
||||
int (*write_packet)(void *opaque, const uint8_t *buf, int buf_size);
|
||||
int64_t (*seek)(void *opaque, int64_t offset, int whence);
|
||||
int64_t pos; /**< position in the file of the current buffer */
|
||||
int eof_reached; /**< true if was unable to read due to error or eof */
|
||||
int error; /**< contains the error code or 0 if no error happened */
|
||||
int write_flag; /**< true if open for writing */
|
||||
int max_packet_size;
|
||||
int min_packet_size; /**< Try to buffer at least this amount of data
|
||||
before flushing it. */
|
||||
unsigned long checksum;
|
||||
unsigned char *checksum_ptr;
|
||||
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
|
||||
/**
|
||||
* Pause or resume playback for network streaming protocols - e.g. MMS.
|
||||
*/
|
||||
int (*read_pause)(void *opaque, int pause);
|
||||
/**
|
||||
* Seek to a given timestamp in stream with the specified stream_index.
|
||||
* Needed for some network streaming protocols which don't support seeking
|
||||
* to byte position.
|
||||
*/
|
||||
int64_t (*read_seek)(void *opaque, int stream_index,
|
||||
int64_t timestamp, int flags);
|
||||
/**
|
||||
* A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
|
||||
*/
|
||||
int seekable;
|
||||
|
||||
/**
|
||||
* avio_read and avio_write should if possible be satisfied directly
|
||||
* instead of going through a buffer, and avio_seek will always
|
||||
* call the underlying seek function directly.
|
||||
*/
|
||||
int direct;
|
||||
|
||||
/**
|
||||
* ',' separated list of allowed protocols.
|
||||
*/
|
||||
const char *protocol_whitelist;
|
||||
|
||||
/**
|
||||
* ',' separated list of disallowed protocols.
|
||||
*/
|
||||
const char *protocol_blacklist;
|
||||
|
||||
/**
|
||||
* A callback that is used instead of write_packet.
|
||||
*/
|
||||
int (*write_data_type)(void *opaque, const uint8_t *buf, int buf_size,
|
||||
enum AVIODataMarkerType type, int64_t time);
|
||||
/**
|
||||
* If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT,
|
||||
* but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly
|
||||
* small chunks of data returned from the callback).
|
||||
*/
|
||||
int ignore_boundary_point;
|
||||
|
||||
/**
|
||||
* Maximum reached position before a backward seek in the write buffer,
|
||||
* used keeping track of already written data for a later flush.
|
||||
*/
|
||||
unsigned char *buf_ptr_max;
|
||||
|
||||
/**
|
||||
* Read-only statistic of bytes read for this AVIOContext.
|
||||
*/
|
||||
int64_t bytes_read;
|
||||
|
||||
/**
|
||||
* Read-only statistic of bytes written for this AVIOContext.
|
||||
*/
|
||||
int64_t bytes_written;
|
||||
} AVIOContext;
|
||||
|
||||
/**
|
||||
* Return the name of the protocol that will handle the passed URL.
|
||||
*
|
||||
* NULL is returned if no protocol could be found for the given URL.
|
||||
*
|
||||
* @return Name of the protocol or NULL.
|
||||
*/
|
||||
const char *avio_find_protocol_name(const char *url);
|
||||
|
||||
/**
|
||||
* Return AVIO_FLAG_* access flags corresponding to the access permissions
|
||||
* of the resource in url, or a negative value corresponding to an
|
||||
* AVERROR code in case of failure. The returned access flags are
|
||||
* masked by the value in flags.
|
||||
*
|
||||
* @note This function is intrinsically unsafe, in the sense that the
|
||||
* checked resource may change its existence or permission status from
|
||||
* one call to another. Thus you should not trust the returned value,
|
||||
* unless you are sure that no other processes are accessing the
|
||||
* checked resource.
|
||||
*/
|
||||
int avio_check(const char *url, int flags);
|
||||
|
||||
/**
|
||||
* Open directory for reading.
|
||||
*
|
||||
* @param s directory read context. Pointer to a NULL pointer must be passed.
|
||||
* @param url directory to be listed.
|
||||
* @param options A dictionary filled with protocol-private options. On return
|
||||
* this parameter will be destroyed and replaced with a dictionary
|
||||
* containing options that were not found. May be NULL.
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options);
|
||||
|
||||
/**
|
||||
* Get next directory entry.
|
||||
*
|
||||
* Returned entry must be freed with avio_free_directory_entry(). In particular
|
||||
* it may outlive AVIODirContext.
|
||||
*
|
||||
* @param s directory read context.
|
||||
* @param[out] next next entry or NULL when no more entries.
|
||||
* @return >=0 on success or negative on error. End of list is not considered an
|
||||
* error.
|
||||
*/
|
||||
int avio_read_dir(AVIODirContext *s, AVIODirEntry **next);
|
||||
|
||||
/**
|
||||
* Close directory.
|
||||
*
|
||||
* @note Entries created using avio_read_dir() are not deleted and must be
|
||||
* freeded with avio_free_directory_entry().
|
||||
*
|
||||
* @param s directory read context.
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avio_close_dir(AVIODirContext **s);
|
||||
|
||||
/**
|
||||
* Free entry allocated by avio_read_dir().
|
||||
*
|
||||
* @param entry entry to be freed.
|
||||
*/
|
||||
void avio_free_directory_entry(AVIODirEntry **entry);
|
||||
|
||||
/**
|
||||
* Allocate and initialize an AVIOContext for buffered I/O. It must be later
|
||||
* freed with avio_context_free().
|
||||
*
|
||||
* @param buffer Memory block for input/output operations via AVIOContext.
|
||||
* The buffer must be allocated with av_malloc() and friends.
|
||||
* It may be freed and replaced with a new buffer by libavformat.
|
||||
* AVIOContext.buffer holds the buffer currently in use,
|
||||
* which must be later freed with av_free().
|
||||
* @param buffer_size The buffer size is very important for performance.
|
||||
* For protocols with fixed blocksize it should be set to this blocksize.
|
||||
* For others a typical size is a cache page, e.g. 4kb.
|
||||
* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.
|
||||
* @param opaque An opaque pointer to user-specific data.
|
||||
* @param read_packet A function for refilling the buffer, may be NULL.
|
||||
* For stream protocols, must never return 0 but rather
|
||||
* a proper AVERROR code.
|
||||
* @param write_packet A function for writing the buffer contents, may be NULL.
|
||||
* The function may not change the input buffers content.
|
||||
* @param seek A function for seeking to specified byte position, may be NULL.
|
||||
*
|
||||
* @return Allocated AVIOContext or NULL on failure.
|
||||
*/
|
||||
AVIOContext *avio_alloc_context(
|
||||
unsigned char *buffer,
|
||||
int buffer_size,
|
||||
int write_flag,
|
||||
void *opaque,
|
||||
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
|
||||
int (*write_packet)(void *opaque, const uint8_t *buf, int buf_size),
|
||||
int64_t (*seek)(void *opaque, int64_t offset, int whence));
|
||||
|
||||
/**
|
||||
* Free the supplied IO context and everything associated with it.
|
||||
*
|
||||
* @param s Double pointer to the IO context. This function will write NULL
|
||||
* into s.
|
||||
*/
|
||||
void avio_context_free(AVIOContext **s);
|
||||
|
||||
void avio_w8(AVIOContext *s, int b);
|
||||
void avio_write(AVIOContext *s, const unsigned char *buf, int size);
|
||||
void avio_wl64(AVIOContext *s, uint64_t val);
|
||||
void avio_wb64(AVIOContext *s, uint64_t val);
|
||||
void avio_wl32(AVIOContext *s, unsigned int val);
|
||||
void avio_wb32(AVIOContext *s, unsigned int val);
|
||||
void avio_wl24(AVIOContext *s, unsigned int val);
|
||||
void avio_wb24(AVIOContext *s, unsigned int val);
|
||||
void avio_wl16(AVIOContext *s, unsigned int val);
|
||||
void avio_wb16(AVIOContext *s, unsigned int val);
|
||||
|
||||
/**
|
||||
* Write a NULL-terminated string.
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
int avio_put_str(AVIOContext *s, const char *str);
|
||||
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16LE and write it.
|
||||
* @param s the AVIOContext
|
||||
* @param str NULL-terminated UTF-8 string
|
||||
*
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
int avio_put_str16le(AVIOContext *s, const char *str);
|
||||
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16BE and write it.
|
||||
* @param s the AVIOContext
|
||||
* @param str NULL-terminated UTF-8 string
|
||||
*
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
int avio_put_str16be(AVIOContext *s, const char *str);
|
||||
|
||||
/**
|
||||
* Mark the written bytestream as a specific type.
|
||||
*
|
||||
* Zero-length ranges are omitted from the output.
|
||||
*
|
||||
* @param s the AVIOContext
|
||||
* @param time the stream time the current bytestream pos corresponds to
|
||||
* (in AV_TIME_BASE units), or AV_NOPTS_VALUE if unknown or not
|
||||
* applicable
|
||||
* @param type the kind of data written starting at the current pos
|
||||
*/
|
||||
void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type);
|
||||
|
||||
/**
|
||||
* ORing this as the "whence" parameter to a seek function causes it to
|
||||
* return the filesize without seeking anywhere. Supporting this is optional.
|
||||
* If it is not supported then the seek function will return <0.
|
||||
*/
|
||||
#define AVSEEK_SIZE 0x10000
|
||||
|
||||
/**
|
||||
* Passing this flag as the "whence" parameter to a seek function causes it to
|
||||
* seek by any means (like reopening and linear reading) or other normally unreasonable
|
||||
* means that can be extremely slow.
|
||||
* This may be ignored by the seek code.
|
||||
*/
|
||||
#define AVSEEK_FORCE 0x20000
|
||||
|
||||
/**
|
||||
* fseek() equivalent for AVIOContext.
|
||||
* @return new position or AVERROR.
|
||||
*/
|
||||
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence);
|
||||
|
||||
/**
|
||||
* Skip given number of bytes forward
|
||||
* @return new position or AVERROR.
|
||||
*/
|
||||
int64_t avio_skip(AVIOContext *s, int64_t offset);
|
||||
|
||||
/**
|
||||
* ftell() equivalent for AVIOContext.
|
||||
* @return position or AVERROR.
|
||||
*/
|
||||
static av_always_inline int64_t avio_tell(AVIOContext *s)
|
||||
{
|
||||
return avio_seek(s, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesize.
|
||||
* @return filesize or AVERROR
|
||||
*/
|
||||
int64_t avio_size(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Similar to feof() but also returns nonzero on read errors.
|
||||
* @return non zero if and only if at end of file or a read error happened when reading.
|
||||
*/
|
||||
int avio_feof(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Writes a formatted string to the context taking a va_list.
|
||||
* @return number of bytes written, < 0 on error.
|
||||
*/
|
||||
int avio_vprintf(AVIOContext *s, const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* Writes a formatted string to the context.
|
||||
* @return number of bytes written, < 0 on error.
|
||||
*/
|
||||
int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3);
|
||||
|
||||
/**
|
||||
* Write a NULL terminated array of strings to the context.
|
||||
* Usually you don't need to use this function directly but its macro wrapper,
|
||||
* avio_print.
|
||||
*/
|
||||
void avio_print_string_array(AVIOContext *s, const char * const strings[]);
|
||||
|
||||
/**
|
||||
* Write strings (const char *) to the context.
|
||||
* This is a convenience macro around avio_print_string_array and it
|
||||
* automatically creates the string array from the variable argument list.
|
||||
* For simple string concatenations this function is more performant than using
|
||||
* avio_printf since it does not need a temporary buffer.
|
||||
*/
|
||||
#define avio_print(s, ...) \
|
||||
avio_print_string_array(s, (const char*[]){__VA_ARGS__, NULL})
|
||||
|
||||
/**
|
||||
* Force flushing of buffered data.
|
||||
*
|
||||
* For write streams, force the buffered data to be immediately written to the output,
|
||||
* without to wait to fill the internal buffer.
|
||||
*
|
||||
* For read streams, discard all currently buffered data, and advance the
|
||||
* reported file position to that of the underlying stream. This does not
|
||||
* read new data, and does not perform any seeks.
|
||||
*/
|
||||
void avio_flush(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Read size bytes from AVIOContext into buf.
|
||||
* @return number of bytes read or AVERROR
|
||||
*/
|
||||
int avio_read(AVIOContext *s, unsigned char *buf, int size);
|
||||
|
||||
/**
|
||||
* Read size bytes from AVIOContext into buf. Unlike avio_read(), this is allowed
|
||||
* to read fewer bytes than requested. The missing bytes can be read in the next
|
||||
* call. This always tries to read at least 1 byte.
|
||||
* Useful to reduce latency in certain cases.
|
||||
* @return number of bytes read or AVERROR
|
||||
*/
|
||||
int avio_read_partial(AVIOContext *s, unsigned char *buf, int size);
|
||||
|
||||
/**
|
||||
* @name Functions for reading from AVIOContext
|
||||
* @{
|
||||
*
|
||||
* @note return 0 if EOF, so you cannot use it if EOF handling is
|
||||
* necessary
|
||||
*/
|
||||
int avio_r8 (AVIOContext *s);
|
||||
unsigned int avio_rl16(AVIOContext *s);
|
||||
unsigned int avio_rl24(AVIOContext *s);
|
||||
unsigned int avio_rl32(AVIOContext *s);
|
||||
uint64_t avio_rl64(AVIOContext *s);
|
||||
unsigned int avio_rb16(AVIOContext *s);
|
||||
unsigned int avio_rb24(AVIOContext *s);
|
||||
unsigned int avio_rb32(AVIOContext *s);
|
||||
uint64_t avio_rb64(AVIOContext *s);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read a string from pb into buf. The reading will terminate when either
|
||||
* a NULL character was encountered, maxlen bytes have been read, or nothing
|
||||
* more can be read from pb. The result is guaranteed to be NULL-terminated, it
|
||||
* will be truncated if buf is too small.
|
||||
* Note that the string is not interpreted or validated in any way, it
|
||||
* might get truncated in the middle of a sequence for multi-byte encodings.
|
||||
*
|
||||
* @return number of bytes read (is always <= maxlen).
|
||||
* If reading ends on EOF or error, the return value will be one more than
|
||||
* bytes actually read.
|
||||
*/
|
||||
int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen);
|
||||
|
||||
/**
|
||||
* Read a UTF-16 string from pb and convert it to UTF-8.
|
||||
* The reading will terminate when either a null or invalid character was
|
||||
* encountered or maxlen bytes have been read.
|
||||
* @return number of bytes read (is always <= maxlen)
|
||||
*/
|
||||
int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen);
|
||||
int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
|
||||
|
||||
|
||||
/**
|
||||
* @name URL open modes
|
||||
* The flags argument to avio_open must be one of the following
|
||||
* constants, optionally ORed with other flags.
|
||||
* @{
|
||||
*/
|
||||
#define AVIO_FLAG_READ 1 /**< read-only */
|
||||
#define AVIO_FLAG_WRITE 2 /**< write-only */
|
||||
#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use non-blocking mode.
|
||||
* If this flag is set, operations on the context will return
|
||||
* AVERROR(EAGAIN) if they can not be performed immediately.
|
||||
* If this flag is not set, operations on the context will never return
|
||||
* AVERROR(EAGAIN).
|
||||
* Note that this flag does not affect the opening/connecting of the
|
||||
* context. Connecting a protocol will always block if necessary (e.g. on
|
||||
* network protocols) but never hang (e.g. on busy devices).
|
||||
* Warning: non-blocking protocols is work-in-progress; this flag may be
|
||||
* silently ignored.
|
||||
*/
|
||||
#define AVIO_FLAG_NONBLOCK 8
|
||||
|
||||
/**
|
||||
* Use direct mode.
|
||||
* avio_read and avio_write should if possible be satisfied directly
|
||||
* instead of going through a buffer, and avio_seek will always
|
||||
* call the underlying seek function directly.
|
||||
*/
|
||||
#define AVIO_FLAG_DIRECT 0x8000
|
||||
|
||||
/**
|
||||
* Create and initialize a AVIOContext for accessing the
|
||||
* resource indicated by url.
|
||||
* @note When the resource indicated by url has been opened in
|
||||
* read+write mode, the AVIOContext can be used only for writing.
|
||||
*
|
||||
* @param s Used to return the pointer to the created AVIOContext.
|
||||
* In case of failure the pointed to value is set to NULL.
|
||||
* @param url resource to access
|
||||
* @param flags flags which control how the resource indicated by url
|
||||
* is to be opened
|
||||
* @return >= 0 in case of success, a negative value corresponding to an
|
||||
* AVERROR code in case of failure
|
||||
*/
|
||||
int avio_open(AVIOContext **s, const char *url, int flags);
|
||||
|
||||
/**
|
||||
* Create and initialize a AVIOContext for accessing the
|
||||
* resource indicated by url.
|
||||
* @note When the resource indicated by url has been opened in
|
||||
* read+write mode, the AVIOContext can be used only for writing.
|
||||
*
|
||||
* @param s Used to return the pointer to the created AVIOContext.
|
||||
* In case of failure the pointed to value is set to NULL.
|
||||
* @param url resource to access
|
||||
* @param flags flags which control how the resource indicated by url
|
||||
* is to be opened
|
||||
* @param int_cb an interrupt callback to be used at the protocols level
|
||||
* @param options A dictionary filled with protocol-private options. On return
|
||||
* this parameter will be destroyed and replaced with a dict containing options
|
||||
* that were not found. May be NULL.
|
||||
* @return >= 0 in case of success, a negative value corresponding to an
|
||||
* AVERROR code in case of failure
|
||||
*/
|
||||
int avio_open2(AVIOContext **s, const char *url, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options);
|
||||
|
||||
/**
|
||||
* Close the resource accessed by the AVIOContext s and free it.
|
||||
* This function can only be used if s was opened by avio_open().
|
||||
*
|
||||
* The internal buffer is automatically flushed before closing the
|
||||
* resource.
|
||||
*
|
||||
* @return 0 on success, an AVERROR < 0 on error.
|
||||
* @see avio_closep
|
||||
*/
|
||||
int avio_close(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Close the resource accessed by the AVIOContext *s, free it
|
||||
* and set the pointer pointing to it to NULL.
|
||||
* This function can only be used if s was opened by avio_open().
|
||||
*
|
||||
* The internal buffer is automatically flushed before closing the
|
||||
* resource.
|
||||
*
|
||||
* @return 0 on success, an AVERROR < 0 on error.
|
||||
* @see avio_close
|
||||
*/
|
||||
int avio_closep(AVIOContext **s);
|
||||
|
||||
|
||||
/**
|
||||
* Open a write only memory stream.
|
||||
*
|
||||
* @param s new IO context
|
||||
* @return zero if no error.
|
||||
*/
|
||||
int avio_open_dyn_buf(AVIOContext **s);
|
||||
|
||||
/**
|
||||
* Return the written size and a pointer to the buffer.
|
||||
* The AVIOContext stream is left intact.
|
||||
* The buffer must NOT be freed.
|
||||
* No padding is added to the buffer.
|
||||
*
|
||||
* @param s IO context
|
||||
* @param pbuffer pointer to a byte buffer
|
||||
* @return the length of the byte buffer
|
||||
*/
|
||||
int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer);
|
||||
|
||||
/**
|
||||
* Return the written size and a pointer to the buffer. The buffer
|
||||
* must be freed with av_free().
|
||||
* Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer.
|
||||
*
|
||||
* @param s IO context
|
||||
* @param pbuffer pointer to a byte buffer
|
||||
* @return the length of the byte buffer
|
||||
*/
|
||||
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer);
|
||||
|
||||
/**
|
||||
* Iterate through names of available protocols.
|
||||
*
|
||||
* @param opaque A private pointer representing current protocol.
|
||||
* It must be a pointer to NULL on first iteration and will
|
||||
* be updated by successive calls to avio_enum_protocols.
|
||||
* @param output If set to 1, iterate over output protocols,
|
||||
* otherwise over input protocols.
|
||||
*
|
||||
* @return A static string containing the name of current protocol or NULL
|
||||
*/
|
||||
const char *avio_enum_protocols(void **opaque, int output);
|
||||
|
||||
/**
|
||||
* Get AVClass by names of available protocols.
|
||||
*
|
||||
* @return A AVClass of input protocol name or NULL
|
||||
*/
|
||||
const AVClass *avio_protocol_get_class(const char *name);
|
||||
|
||||
/**
|
||||
* Pause and resume playing - only meaningful if using a network streaming
|
||||
* protocol (e.g. MMS).
|
||||
*
|
||||
* @param h IO context from which to call the read_pause function pointer
|
||||
* @param pause 1 for pause, 0 for resume
|
||||
*/
|
||||
int avio_pause(AVIOContext *h, int pause);
|
||||
|
||||
/**
|
||||
* Seek to a given timestamp relative to some component stream.
|
||||
* Only meaningful if using a network streaming protocol (e.g. MMS.).
|
||||
*
|
||||
* @param h IO context from which to call the seek function pointers
|
||||
* @param stream_index The stream index that the timestamp is relative to.
|
||||
* If stream_index is (-1) the timestamp should be in AV_TIME_BASE
|
||||
* units from the beginning of the presentation.
|
||||
* If a stream_index >= 0 is used and the protocol does not support
|
||||
* seeking based on component streams, the call will fail.
|
||||
* @param timestamp timestamp in AVStream.time_base units
|
||||
* or if there is no stream specified then in AV_TIME_BASE units.
|
||||
* @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE
|
||||
* and AVSEEK_FLAG_ANY. The protocol may silently ignore
|
||||
* AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will
|
||||
* fail if used and not supported.
|
||||
* @return >= 0 on success
|
||||
* @see AVInputFormat::read_seek
|
||||
*/
|
||||
int64_t avio_seek_time(AVIOContext *h, int stream_index,
|
||||
int64_t timestamp, int flags);
|
||||
|
||||
/* Avoid a warning. The header can not be included because it breaks c++. */
|
||||
struct AVBPrint;
|
||||
|
||||
/**
|
||||
* Read contents of h into print buffer, up to max_size bytes, or up to EOF.
|
||||
*
|
||||
* @return 0 for success (max_size bytes read or EOF reached), negative error
|
||||
* code otherwise
|
||||
*/
|
||||
int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size);
|
||||
|
||||
/**
|
||||
* Accept and allocate a client context on a server context.
|
||||
* @param s the server context
|
||||
* @param c the client context, must be unallocated
|
||||
* @return >= 0 on success or a negative value corresponding
|
||||
* to an AVERROR on failure
|
||||
*/
|
||||
int avio_accept(AVIOContext *s, AVIOContext **c);
|
||||
|
||||
/**
|
||||
* Perform one step of the protocol handshake to accept a new client.
|
||||
* This function must be called on a client returned by avio_accept() before
|
||||
* using it as a read/write context.
|
||||
* It is separate from avio_accept() because it may block.
|
||||
* A step of the handshake is defined by places where the application may
|
||||
* decide to change the proceedings.
|
||||
* For example, on a protocol with a request header and a reply header, each
|
||||
* one can constitute a step because the application may use the parameters
|
||||
* from the request to change parameters in the reply; or each individual
|
||||
* chunk of the request can constitute a step.
|
||||
* If the handshake is already finished, avio_handshake() does nothing and
|
||||
* returns 0 immediately.
|
||||
*
|
||||
* @param c the client context to perform the handshake on
|
||||
* @return 0 on a complete and successful handshake
|
||||
* > 0 if the handshake progressed, but is not complete
|
||||
* < 0 for an AVERROR code
|
||||
*/
|
||||
int avio_handshake(AVIOContext *c);
|
||||
#endif /* AVFORMAT_AVIO_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Version macros.
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_VERSION_H
|
||||
#define AVFORMAT_VERSION_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup libavf
|
||||
* Libavformat version macros
|
||||
*/
|
||||
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVFORMAT_VERSION_MINOR 7
|
||||
#define LIBAVFORMAT_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||
LIBAVFORMAT_VERSION_MINOR, \
|
||||
LIBAVFORMAT_VERSION_MICRO)
|
||||
#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \
|
||||
LIBAVFORMAT_VERSION_MINOR, \
|
||||
LIBAVFORMAT_VERSION_MICRO)
|
||||
#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT
|
||||
|
||||
#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)
|
||||
|
||||
#endif /* AVFORMAT_VERSION_H */
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Version macros.
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_VERSION_MAJOR_H
|
||||
#define AVFORMAT_VERSION_MAJOR_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup libavf
|
||||
* Libavformat version macros
|
||||
*/
|
||||
|
||||
// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
|
||||
// Also please add any ticket numbers that you believe might be affected here
|
||||
#define LIBAVFORMAT_VERSION_MAJOR 61
|
||||
|
||||
/**
|
||||
* FF_API_* defines may be placed below to indicate public API that will be
|
||||
* dropped at a future version bump. The defines themselves are not part of
|
||||
* the public API and may change, break or disappear at any time.
|
||||
*
|
||||
* @note, when bumping the major version it is recommended to manually
|
||||
* disable each FF_API_* in its own commit instead of disabling them all
|
||||
* at once through the bump. This improves the git bisect-ability of the change.
|
||||
*
|
||||
*/
|
||||
#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
#define FF_API_LAVF_SHORTEST (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
#define FF_API_ALLOW_FLUSH (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
#define FF_API_AVSTREAM_SIDE_DATA (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
|
||||
#define FF_API_GET_DUR_ESTIMATE_METHOD (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
#define FF_API_INTERNAL_TIMING (LIBAVFORMAT_VERSION_MAJOR < 62)
|
||||
|
||||
#define FF_API_R_FRAME_RATE 1
|
||||
|
||||
#endif /* AVFORMAT_VERSION_MAJOR_H */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* copyright (c) 2006 Mans Rullgard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavu_adler32
|
||||
* Public header for Adler-32 hash function implementation.
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_ADLER32_H
|
||||
#define AVUTIL_ADLER32_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "attributes.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavu_adler32 Adler-32
|
||||
* @ingroup lavu_hash
|
||||
* Adler-32 hash function implementation.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef uint32_t AVAdler;
|
||||
|
||||
/**
|
||||
* Calculate the Adler32 checksum of a buffer.
|
||||
*
|
||||
* Passing the return value to a subsequent av_adler32_update() call
|
||||
* allows the checksum of multiple buffers to be calculated as though
|
||||
* they were concatenated.
|
||||
*
|
||||
* @param adler initial checksum value
|
||||
* @param buf pointer to input buffer
|
||||
* @param len size of input buffer
|
||||
* @return updated checksum
|
||||
*/
|
||||
AVAdler av_adler32_update(AVAdler adler, const uint8_t *buf,
|
||||
size_t len) av_pure;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_ADLER32_H */
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AES_H
|
||||
#define AVUTIL_AES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavu_aes AES
|
||||
* @ingroup lavu_crypto
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern const int av_aes_size;
|
||||
|
||||
struct AVAES;
|
||||
|
||||
/**
|
||||
* Allocate an AVAES context.
|
||||
*/
|
||||
struct AVAES *av_aes_alloc(void);
|
||||
|
||||
/**
|
||||
* Initialize an AVAES context.
|
||||
*
|
||||
* @param a The AVAES context
|
||||
* @param key Pointer to the key
|
||||
* @param key_bits 128, 192 or 256
|
||||
* @param decrypt 0 for encryption, 1 for decryption
|
||||
*/
|
||||
int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt);
|
||||
|
||||
/**
|
||||
* Encrypt or decrypt a buffer using a previously initialized context.
|
||||
*
|
||||
* @param a The AVAES context
|
||||
* @param dst destination array, can be equal to src
|
||||
* @param src source array, can be equal to dst
|
||||
* @param count number of 16 byte blocks
|
||||
* @param iv initialization vector for CBC mode, if NULL then ECB will be used
|
||||
* @param decrypt 0 for encryption, 1 for decryption
|
||||
*/
|
||||
void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_AES_H */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* AES-CTR cipher
|
||||
* Copyright (c) 2015 Eran Kornblau <erankor at gmail dot com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AES_CTR_H
|
||||
#define AVUTIL_AES_CTR_H
|
||||
|
||||
/**
|
||||
* @defgroup lavu_aes_ctr AES-CTR
|
||||
* @ingroup lavu_crypto
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "attributes.h"
|
||||
|
||||
#define AES_CTR_KEY_SIZE (16)
|
||||
#define AES_CTR_IV_SIZE (8)
|
||||
|
||||
struct AVAESCTR;
|
||||
|
||||
/**
|
||||
* Allocate an AVAESCTR context.
|
||||
*/
|
||||
struct AVAESCTR *av_aes_ctr_alloc(void);
|
||||
|
||||
/**
|
||||
* Initialize an AVAESCTR context.
|
||||
*
|
||||
* @param a The AVAESCTR context to initialize
|
||||
* @param key encryption key, must have a length of AES_CTR_KEY_SIZE
|
||||
*/
|
||||
int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key);
|
||||
|
||||
/**
|
||||
* Release an AVAESCTR context.
|
||||
*
|
||||
* @param a The AVAESCTR context
|
||||
*/
|
||||
void av_aes_ctr_free(struct AVAESCTR *a);
|
||||
|
||||
/**
|
||||
* Process a buffer using a previously initialized context.
|
||||
*
|
||||
* @param a The AVAESCTR context
|
||||
* @param dst destination array, can be equal to src
|
||||
* @param src source array, can be equal to dst
|
||||
* @param size the size of src and dst
|
||||
*/
|
||||
void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int size);
|
||||
|
||||
/**
|
||||
* Get the current iv
|
||||
*/
|
||||
const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a);
|
||||
|
||||
/**
|
||||
* Generate a random iv
|
||||
*/
|
||||
void av_aes_ctr_set_random_iv(struct AVAESCTR *a);
|
||||
|
||||
/**
|
||||
* Forcefully change the 8-byte iv
|
||||
*/
|
||||
void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv);
|
||||
|
||||
/**
|
||||
* Forcefully change the "full" 16-byte iv, including the counter
|
||||
*/
|
||||
void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv);
|
||||
|
||||
/**
|
||||
* Increment the top 64 bit of the iv (performed after each frame)
|
||||
*/
|
||||
void av_aes_ctr_increment_iv(struct AVAESCTR *a);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_AES_CTR_H */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Jan Ekström <jeebjp@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H
|
||||
#define AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "frame.h"
|
||||
#include "rational.h"
|
||||
|
||||
/**
|
||||
* Ambient viewing environment metadata as defined by H.274. The values are
|
||||
* saved in AVRationals so that they keep their exactness, while allowing for
|
||||
* easy access to a double value with f.ex. av_q2d.
|
||||
*
|
||||
* @note sizeof(AVAmbientViewingEnvironment) is not part of the public ABI, and
|
||||
* it must be allocated using av_ambient_viewing_environment_alloc.
|
||||
*/
|
||||
typedef struct AVAmbientViewingEnvironment {
|
||||
/**
|
||||
* Environmental illuminance of the ambient viewing environment in lux.
|
||||
*/
|
||||
AVRational ambient_illuminance;
|
||||
|
||||
/**
|
||||
* Normalized x chromaticity coordinate of the environmental ambient light
|
||||
* in the nominal viewing environment according to the CIE 1931 definition
|
||||
* of x and y as specified in ISO/CIE 11664-1.
|
||||
*/
|
||||
AVRational ambient_light_x;
|
||||
|
||||
/**
|
||||
* Normalized y chromaticity coordinate of the environmental ambient light
|
||||
* in the nominal viewing environment according to the CIE 1931 definition
|
||||
* of x and y as specified in ISO/CIE 11664-1.
|
||||
*/
|
||||
AVRational ambient_light_y;
|
||||
} AVAmbientViewingEnvironment;
|
||||
|
||||
/**
|
||||
* Allocate an AVAmbientViewingEnvironment structure.
|
||||
*
|
||||
* @return the newly allocated struct or NULL on failure
|
||||
*/
|
||||
AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size);
|
||||
|
||||
/**
|
||||
* Allocate and add an AVAmbientViewingEnvironment structure to an existing
|
||||
* AVFrame as side data.
|
||||
*
|
||||
* @return the newly allocated struct, or NULL on failure
|
||||
*/
|
||||
AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVFrame *frame);
|
||||
|
||||
#endif /* AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Macro definitions for various function/variable attributes
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_ATTRIBUTES_H
|
||||
#define AVUTIL_ATTRIBUTES_H
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
|
||||
# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y))
|
||||
#else
|
||||
# define AV_GCC_VERSION_AT_LEAST(x,y) 0
|
||||
# define AV_GCC_VERSION_AT_MOST(x,y) 0
|
||||
#endif
|
||||
|
||||
#ifdef __has_builtin
|
||||
# define AV_HAS_BUILTIN(x) __has_builtin(x)
|
||||
#else
|
||||
# define AV_HAS_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef av_always_inline
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,1)
|
||||
# define av_always_inline __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER)
|
||||
# define av_always_inline __forceinline
|
||||
#else
|
||||
# define av_always_inline inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef av_extern_inline
|
||||
#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__)
|
||||
# define av_extern_inline extern inline
|
||||
#else
|
||||
# define av_extern_inline inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,4)
|
||||
# define av_warn_unused_result __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define av_warn_unused_result
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,1)
|
||||
# define av_noinline __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
# define av_noinline __declspec(noinline)
|
||||
#else
|
||||
# define av_noinline
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__)
|
||||
# define av_pure __attribute__((pure))
|
||||
#else
|
||||
# define av_pure
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
|
||||
# define av_const __attribute__((const))
|
||||
#else
|
||||
# define av_const
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(4,3) || defined(__clang__)
|
||||
# define av_cold __attribute__((cold))
|
||||
#else
|
||||
# define av_cold
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__)
|
||||
# define av_flatten __attribute__((flatten))
|
||||
#else
|
||||
# define av_flatten
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,1)
|
||||
# define attribute_deprecated __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
# define attribute_deprecated __declspec(deprecated)
|
||||
#else
|
||||
# define attribute_deprecated
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Disable warnings about deprecated features
|
||||
* This is useful for sections of code kept for backward compatibility and
|
||||
* scheduled for removal.
|
||||
*/
|
||||
#ifndef AV_NOWARN_DEPRECATED
|
||||
#if AV_GCC_VERSION_AT_LEAST(4,6) || defined(__clang__)
|
||||
# define AV_NOWARN_DEPRECATED(code) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
|
||||
code \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#elif defined(_MSC_VER)
|
||||
# define AV_NOWARN_DEPRECATED(code) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable : 4996)) \
|
||||
code; \
|
||||
__pragma(warning(pop))
|
||||
#else
|
||||
# define AV_NOWARN_DEPRECATED(code) code
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define av_unused __attribute__((unused))
|
||||
#else
|
||||
# define av_unused
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Mark a variable as used and prevent the compiler from optimizing it
|
||||
* away. This is useful for variables accessed only from inline
|
||||
* assembler without the compiler being aware.
|
||||
*/
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__)
|
||||
# define av_used __attribute__((used))
|
||||
#else
|
||||
# define av_used
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(3,3) || defined(__clang__)
|
||||
# define av_alias __attribute__((may_alias))
|
||||
#else
|
||||
# define av_alias
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER)
|
||||
# define av_uninit(x) x=x
|
||||
#else
|
||||
# define av_uninit(x) x
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define av_builtin_constant_p __builtin_constant_p
|
||||
# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos)))
|
||||
#else
|
||||
# define av_builtin_constant_p(x) 0
|
||||
# define av_printf_format(fmtpos, attrpos)
|
||||
#endif
|
||||
|
||||
#if AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__)
|
||||
# define av_noreturn __attribute__((noreturn))
|
||||
#else
|
||||
# define av_noreturn
|
||||
#endif
|
||||
|
||||
#endif /* AVUTIL_ATTRIBUTES_H */
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Audio FIFO
|
||||
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Audio FIFO Buffer
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AUDIO_FIFO_H
|
||||
#define AVUTIL_AUDIO_FIFO_H
|
||||
|
||||
#include "attributes.h"
|
||||
#include "samplefmt.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavu_audio
|
||||
* @{
|
||||
*
|
||||
* @defgroup lavu_audiofifo Audio FIFO Buffer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for an Audio FIFO Buffer.
|
||||
*
|
||||
* - Operates at the sample level rather than the byte level.
|
||||
* - Supports multiple channels with either planar or packed sample format.
|
||||
* - Automatic reallocation when writing to a full buffer.
|
||||
*/
|
||||
typedef struct AVAudioFifo AVAudioFifo;
|
||||
|
||||
/**
|
||||
* Free an AVAudioFifo.
|
||||
*
|
||||
* @param af AVAudioFifo to free
|
||||
*/
|
||||
void av_audio_fifo_free(AVAudioFifo *af);
|
||||
|
||||
/**
|
||||
* Allocate an AVAudioFifo.
|
||||
*
|
||||
* @param sample_fmt sample format
|
||||
* @param channels number of channels
|
||||
* @param nb_samples initial allocation size, in samples
|
||||
* @return newly allocated AVAudioFifo, or NULL on error
|
||||
*/
|
||||
AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels,
|
||||
int nb_samples);
|
||||
|
||||
/**
|
||||
* Reallocate an AVAudioFifo.
|
||||
*
|
||||
* @param af AVAudioFifo to reallocate
|
||||
* @param nb_samples new allocation size, in samples
|
||||
* @return 0 if OK, or negative AVERROR code on failure
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples);
|
||||
|
||||
/**
|
||||
* Write data to an AVAudioFifo.
|
||||
*
|
||||
* The AVAudioFifo will be reallocated automatically if the available space
|
||||
* is less than nb_samples.
|
||||
*
|
||||
* @see enum AVSampleFormat
|
||||
* The documentation for AVSampleFormat describes the data layout.
|
||||
*
|
||||
* @param af AVAudioFifo to write to
|
||||
* @param data audio data plane pointers
|
||||
* @param nb_samples number of samples to write
|
||||
* @return number of samples actually written, or negative AVERROR
|
||||
* code on failure. If successful, the number of samples
|
||||
* actually written will always be nb_samples.
|
||||
*/
|
||||
int av_audio_fifo_write(AVAudioFifo *af, void * const *data, int nb_samples);
|
||||
|
||||
/**
|
||||
* Peek data from an AVAudioFifo.
|
||||
*
|
||||
* @see enum AVSampleFormat
|
||||
* The documentation for AVSampleFormat describes the data layout.
|
||||
*
|
||||
* @param af AVAudioFifo to read from
|
||||
* @param data audio data plane pointers
|
||||
* @param nb_samples number of samples to peek
|
||||
* @return number of samples actually peek, or negative AVERROR code
|
||||
* on failure. The number of samples actually peek will not
|
||||
* be greater than nb_samples, and will only be less than
|
||||
* nb_samples if av_audio_fifo_size is less than nb_samples.
|
||||
*/
|
||||
int av_audio_fifo_peek(const AVAudioFifo *af, void * const *data, int nb_samples);
|
||||
|
||||
/**
|
||||
* Peek data from an AVAudioFifo.
|
||||
*
|
||||
* @see enum AVSampleFormat
|
||||
* The documentation for AVSampleFormat describes the data layout.
|
||||
*
|
||||
* @param af AVAudioFifo to read from
|
||||
* @param data audio data plane pointers
|
||||
* @param nb_samples number of samples to peek
|
||||
* @param offset offset from current read position
|
||||
* @return number of samples actually peek, or negative AVERROR code
|
||||
* on failure. The number of samples actually peek will not
|
||||
* be greater than nb_samples, and will only be less than
|
||||
* nb_samples if av_audio_fifo_size is less than nb_samples.
|
||||
*/
|
||||
int av_audio_fifo_peek_at(const AVAudioFifo *af, void * const *data,
|
||||
int nb_samples, int offset);
|
||||
|
||||
/**
|
||||
* Read data from an AVAudioFifo.
|
||||
*
|
||||
* @see enum AVSampleFormat
|
||||
* The documentation for AVSampleFormat describes the data layout.
|
||||
*
|
||||
* @param af AVAudioFifo to read from
|
||||
* @param data audio data plane pointers
|
||||
* @param nb_samples number of samples to read
|
||||
* @return number of samples actually read, or negative AVERROR code
|
||||
* on failure. The number of samples actually read will not
|
||||
* be greater than nb_samples, and will only be less than
|
||||
* nb_samples if av_audio_fifo_size is less than nb_samples.
|
||||
*/
|
||||
int av_audio_fifo_read(AVAudioFifo *af, void * const *data, int nb_samples);
|
||||
|
||||
/**
|
||||
* Drain data from an AVAudioFifo.
|
||||
*
|
||||
* Removes the data without reading it.
|
||||
*
|
||||
* @param af AVAudioFifo to drain
|
||||
* @param nb_samples number of samples to drain
|
||||
* @return 0 if OK, or negative AVERROR code on failure
|
||||
*/
|
||||
int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples);
|
||||
|
||||
/**
|
||||
* Reset the AVAudioFifo buffer.
|
||||
*
|
||||
* This empties all data in the buffer.
|
||||
*
|
||||
* @param af AVAudioFifo to reset
|
||||
*/
|
||||
void av_audio_fifo_reset(AVAudioFifo *af);
|
||||
|
||||
/**
|
||||
* Get the current number of samples in the AVAudioFifo available for reading.
|
||||
*
|
||||
* @param af the AVAudioFifo to query
|
||||
* @return number of samples available for reading
|
||||
*/
|
||||
int av_audio_fifo_size(AVAudioFifo *af);
|
||||
|
||||
/**
|
||||
* Get the current number of samples in the AVAudioFifo available for writing.
|
||||
*
|
||||
* @param af the AVAudioFifo to query
|
||||
* @return number of samples available for writing
|
||||
*/
|
||||
int av_audio_fifo_space(AVAudioFifo *af);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_AUDIO_FIFO_H */
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* copyright (c) 2010 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* simple assert() macros that are a bit more flexible than ISO C assert().
|
||||
* @author Michael Niedermayer <michaelni@gmx.at>
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AVASSERT_H
|
||||
#define AVUTIL_AVASSERT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_AV_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#include "log.h"
|
||||
#include "macros.h"
|
||||
|
||||
/**
|
||||
* assert() equivalent, that is always enabled.
|
||||
*/
|
||||
#define av_assert0(cond) do { \
|
||||
if (!(cond)) { \
|
||||
av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \
|
||||
AV_STRINGIFY(cond), __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* assert() equivalent, that does not lie in speed critical code.
|
||||
* These asserts() thus can be enabled without fearing speed loss.
|
||||
*/
|
||||
#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0
|
||||
#define av_assert1(cond) av_assert0(cond)
|
||||
#else
|
||||
#define av_assert1(cond) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* assert() equivalent, that does lie in speed critical code.
|
||||
*/
|
||||
#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1
|
||||
#define av_assert2(cond) av_assert0(cond)
|
||||
#define av_assert2_fpu() av_assert0_fpu()
|
||||
#else
|
||||
#define av_assert2(cond) ((void)0)
|
||||
#define av_assert2_fpu() ((void)0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Assert that floating point operations can be executed.
|
||||
*
|
||||
* This will av_assert0() that the cpu is not in MMX state on X86
|
||||
*/
|
||||
void av_assert0_fpu(void);
|
||||
|
||||
#endif /* AVUTIL_AVASSERT_H */
|
||||
@@ -0,0 +1,6 @@
|
||||
/* Generated by ffmpeg configure */
|
||||
#ifndef AVUTIL_AVCONFIG_H
|
||||
#define AVUTIL_AVCONFIG_H
|
||||
#define AV_HAVE_BIGENDIAN 0
|
||||
#define AV_HAVE_FAST_UNALIGNED 1
|
||||
#endif /* AVUTIL_AVCONFIG_H */
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Mans Rullgard
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AVSTRING_H
|
||||
#define AVUTIL_AVSTRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "attributes.h"
|
||||
|
||||
/**
|
||||
* @addtogroup lavu_string
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return non-zero if pfx is a prefix of str. If it is, *ptr is set to
|
||||
* the address of the first character in str after the prefix.
|
||||
*
|
||||
* @param str input string
|
||||
* @param pfx prefix to test
|
||||
* @param ptr updated if the prefix is matched inside str
|
||||
* @return non-zero if the prefix matches, zero otherwise
|
||||
*/
|
||||
int av_strstart(const char *str, const char *pfx, const char **ptr);
|
||||
|
||||
/**
|
||||
* Return non-zero if pfx is a prefix of str independent of case. If
|
||||
* it is, *ptr is set to the address of the first character in str
|
||||
* after the prefix.
|
||||
*
|
||||
* @param str input string
|
||||
* @param pfx prefix to test
|
||||
* @param ptr updated if the prefix is matched inside str
|
||||
* @return non-zero if the prefix matches, zero otherwise
|
||||
*/
|
||||
int av_stristart(const char *str, const char *pfx, const char **ptr);
|
||||
|
||||
/**
|
||||
* Locate the first case-independent occurrence in the string haystack
|
||||
* of the string needle. A zero-length string needle is considered to
|
||||
* match at the start of haystack.
|
||||
*
|
||||
* This function is a case-insensitive version of the standard strstr().
|
||||
*
|
||||
* @param haystack string to search in
|
||||
* @param needle string to search for
|
||||
* @return pointer to the located match within haystack
|
||||
* or a null pointer if no match
|
||||
*/
|
||||
char *av_stristr(const char *haystack, const char *needle);
|
||||
|
||||
/**
|
||||
* Locate the first occurrence of the string needle in the string haystack
|
||||
* where not more than hay_length characters are searched. A zero-length
|
||||
* string needle is considered to match at the start of haystack.
|
||||
*
|
||||
* This function is a length-limited version of the standard strstr().
|
||||
*
|
||||
* @param haystack string to search in
|
||||
* @param needle string to search for
|
||||
* @param hay_length length of string to search in
|
||||
* @return pointer to the located match within haystack
|
||||
* or a null pointer if no match
|
||||
*/
|
||||
char *av_strnstr(const char *haystack, const char *needle, size_t hay_length);
|
||||
|
||||
/**
|
||||
* Copy the string src to dst, but no more than size - 1 bytes, and
|
||||
* null-terminate dst.
|
||||
*
|
||||
* This function is the same as BSD strlcpy().
|
||||
*
|
||||
* @param dst destination buffer
|
||||
* @param src source string
|
||||
* @param size size of destination buffer
|
||||
* @return the length of src
|
||||
*
|
||||
* @warning since the return value is the length of src, src absolutely
|
||||
* _must_ be a properly 0-terminated string, otherwise this will read beyond
|
||||
* the end of the buffer and possibly crash.
|
||||
*/
|
||||
size_t av_strlcpy(char *dst, const char *src, size_t size);
|
||||
|
||||
/**
|
||||
* Append the string src to the string dst, but to a total length of
|
||||
* no more than size - 1 bytes, and null-terminate dst.
|
||||
*
|
||||
* This function is similar to BSD strlcat(), but differs when
|
||||
* size <= strlen(dst).
|
||||
*
|
||||
* @param dst destination buffer
|
||||
* @param src source string
|
||||
* @param size size of destination buffer
|
||||
* @return the total length of src and dst
|
||||
*
|
||||
* @warning since the return value use the length of src and dst, these
|
||||
* absolutely _must_ be a properly 0-terminated strings, otherwise this
|
||||
* will read beyond the end of the buffer and possibly crash.
|
||||
*/
|
||||
size_t av_strlcat(char *dst, const char *src, size_t size);
|
||||
|
||||
/**
|
||||
* Append output to a string, according to a format. Never write out of
|
||||
* the destination buffer, and always put a terminating 0 within
|
||||
* the buffer.
|
||||
* @param dst destination buffer (string to which the output is
|
||||
* appended)
|
||||
* @param size total size of the destination buffer
|
||||
* @param fmt printf-compatible format string, specifying how the
|
||||
* following parameters are used
|
||||
* @return the length of the string that would have been generated
|
||||
* if enough space had been available
|
||||
*/
|
||||
size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4);
|
||||
|
||||
/**
|
||||
* Get the count of continuous non zero chars starting from the beginning.
|
||||
*
|
||||
* @param s the string whose length to count
|
||||
* @param len maximum number of characters to check in the string, that
|
||||
* is the maximum value which is returned by the function
|
||||
*/
|
||||
static inline size_t av_strnlen(const char *s, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < len && s[i]; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print arguments following specified format into a large enough auto
|
||||
* allocated buffer. It is similar to GNU asprintf().
|
||||
* @param fmt printf-compatible format string, specifying how the
|
||||
* following parameters are used.
|
||||
* @return the allocated string
|
||||
* @note You have to free the string yourself with av_free().
|
||||
*/
|
||||
char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2);
|
||||
|
||||
/**
|
||||
* Unescape the given string until a non escaped terminating char,
|
||||
* and return the token corresponding to the unescaped string.
|
||||
*
|
||||
* The normal \ and ' escaping is supported. Leading and trailing
|
||||
* whitespaces are removed, unless they are escaped with '\' or are
|
||||
* enclosed between ''.
|
||||
*
|
||||
* @param buf the buffer to parse, buf will be updated to point to the
|
||||
* terminating char
|
||||
* @param term a 0-terminated list of terminating chars
|
||||
* @return the malloced unescaped string, which must be av_freed by
|
||||
* the user, NULL in case of allocation failure
|
||||
*/
|
||||
char *av_get_token(const char **buf, const char *term);
|
||||
|
||||
/**
|
||||
* Split the string into several tokens which can be accessed by
|
||||
* successive calls to av_strtok().
|
||||
*
|
||||
* A token is defined as a sequence of characters not belonging to the
|
||||
* set specified in delim.
|
||||
*
|
||||
* On the first call to av_strtok(), s should point to the string to
|
||||
* parse, and the value of saveptr is ignored. In subsequent calls, s
|
||||
* should be NULL, and saveptr should be unchanged since the previous
|
||||
* call.
|
||||
*
|
||||
* This function is similar to strtok_r() defined in POSIX.1.
|
||||
*
|
||||
* @param s the string to parse, may be NULL
|
||||
* @param delim 0-terminated list of token delimiters, must be non-NULL
|
||||
* @param saveptr user-provided pointer which points to stored
|
||||
* information necessary for av_strtok() to continue scanning the same
|
||||
* string. saveptr is updated to point to the next character after the
|
||||
* first delimiter found, or to NULL if the string was terminated
|
||||
* @return the found token, or NULL when no token is found
|
||||
*/
|
||||
char *av_strtok(char *s, const char *delim, char **saveptr);
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII isdigit.
|
||||
*/
|
||||
static inline av_const int av_isdigit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII isgraph.
|
||||
*/
|
||||
static inline av_const int av_isgraph(int c)
|
||||
{
|
||||
return c > 32 && c < 127;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII isspace.
|
||||
*/
|
||||
static inline av_const int av_isspace(int c)
|
||||
{
|
||||
return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' ||
|
||||
c == '\v';
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII characters to uppercase.
|
||||
*/
|
||||
static inline av_const int av_toupper(int c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
c ^= 0x20;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII characters to lowercase.
|
||||
*/
|
||||
static inline av_const int av_tolower(int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c ^= 0x20;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent conversion of ASCII isxdigit.
|
||||
*/
|
||||
static inline av_const int av_isxdigit(int c)
|
||||
{
|
||||
c = av_tolower(c);
|
||||
return av_isdigit(c) || (c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
/**
|
||||
* Locale-independent case-insensitive compare.
|
||||
* @note This means only ASCII-range characters are case-insensitive
|
||||
*/
|
||||
int av_strcasecmp(const char *a, const char *b);
|
||||
|
||||
/**
|
||||
* Locale-independent case-insensitive compare.
|
||||
* @note This means only ASCII-range characters are case-insensitive
|
||||
*/
|
||||
int av_strncasecmp(const char *a, const char *b, size_t n);
|
||||
|
||||
/**
|
||||
* Locale-independent strings replace.
|
||||
* @note This means only ASCII-range characters are replaced.
|
||||
*/
|
||||
char *av_strireplace(const char *str, const char *from, const char *to);
|
||||
|
||||
/**
|
||||
* Thread safe basename.
|
||||
* @param path the string to parse, on DOS both \ and / are considered separators.
|
||||
* @return pointer to the basename substring.
|
||||
* If path does not contain a slash, the function returns a copy of path.
|
||||
* If path is a NULL pointer or points to an empty string, a pointer
|
||||
* to a string "." is returned.
|
||||
*/
|
||||
const char *av_basename(const char *path);
|
||||
|
||||
/**
|
||||
* Thread safe dirname.
|
||||
* @param path the string to parse, on DOS both \ and / are considered separators.
|
||||
* @return A pointer to a string that's the parent directory of path.
|
||||
* If path is a NULL pointer or points to an empty string, a pointer
|
||||
* to a string "." is returned.
|
||||
* @note the function may modify the contents of the path, so copies should be passed.
|
||||
*/
|
||||
const char *av_dirname(char *path);
|
||||
|
||||
/**
|
||||
* Match instances of a name in a comma-separated list of names.
|
||||
* List entries are checked from the start to the end of the names list,
|
||||
* the first match ends further processing. If an entry prefixed with '-'
|
||||
* matches, then 0 is returned. The "ALL" list entry is considered to
|
||||
* match all names.
|
||||
*
|
||||
* @param name Name to look for.
|
||||
* @param names List of names.
|
||||
* @return 1 on match, 0 otherwise.
|
||||
*/
|
||||
int av_match_name(const char *name, const char *names);
|
||||
|
||||
/**
|
||||
* Append path component to the existing path.
|
||||
* Path separator '/' is placed between when needed.
|
||||
* Resulting string have to be freed with av_free().
|
||||
* @param path base path
|
||||
* @param component component to be appended
|
||||
* @return new path or NULL on error.
|
||||
*/
|
||||
char *av_append_path_component(const char *path, const char *component);
|
||||
|
||||
enum AVEscapeMode {
|
||||
AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode.
|
||||
AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping.
|
||||
AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping.
|
||||
AV_ESCAPE_MODE_XML, ///< Use XML non-markup character data escaping.
|
||||
};
|
||||
|
||||
/**
|
||||
* Consider spaces special and escape them even in the middle of the
|
||||
* string.
|
||||
*
|
||||
* This is equivalent to adding the whitespace characters to the special
|
||||
* characters lists, except it is guaranteed to use the exact same list
|
||||
* of whitespace characters as the rest of libavutil.
|
||||
*/
|
||||
#define AV_ESCAPE_FLAG_WHITESPACE (1 << 0)
|
||||
|
||||
/**
|
||||
* Escape only specified special characters.
|
||||
* Without this flag, escape also any characters that may be considered
|
||||
* special by av_get_token(), such as the single quote.
|
||||
*/
|
||||
#define AV_ESCAPE_FLAG_STRICT (1 << 1)
|
||||
|
||||
/**
|
||||
* Within AV_ESCAPE_MODE_XML, additionally escape single quotes for single
|
||||
* quoted attributes.
|
||||
*/
|
||||
#define AV_ESCAPE_FLAG_XML_SINGLE_QUOTES (1 << 2)
|
||||
|
||||
/**
|
||||
* Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double
|
||||
* quoted attributes.
|
||||
*/
|
||||
#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES (1 << 3)
|
||||
|
||||
|
||||
/**
|
||||
* Escape string in src, and put the escaped string in an allocated
|
||||
* string in *dst, which must be freed with av_free().
|
||||
*
|
||||
* @param dst pointer where an allocated string is put
|
||||
* @param src string to escape, must be non-NULL
|
||||
* @param special_chars string containing the special characters which
|
||||
* need to be escaped, can be NULL
|
||||
* @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
|
||||
* Any unknown value for mode will be considered equivalent to
|
||||
* AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
|
||||
* notice.
|
||||
* @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros
|
||||
* @return the length of the allocated string, or a negative error code in case of error
|
||||
* @see av_bprint_escape()
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_escape(char **dst, const char *src, const char *special_chars,
|
||||
enum AVEscapeMode mode, int flags);
|
||||
|
||||
#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF
|
||||
#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF
|
||||
#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes
|
||||
#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML
|
||||
|
||||
#define AV_UTF8_FLAG_ACCEPT_ALL \
|
||||
AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES
|
||||
|
||||
/**
|
||||
* Read and decode a single UTF-8 code point (character) from the
|
||||
* buffer in *buf, and update *buf to point to the next byte to
|
||||
* decode.
|
||||
*
|
||||
* In case of an invalid byte sequence, the pointer will be updated to
|
||||
* the next byte after the invalid sequence and the function will
|
||||
* return an error code.
|
||||
*
|
||||
* Depending on the specified flags, the function will also fail in
|
||||
* case the decoded code point does not belong to a valid range.
|
||||
*
|
||||
* @note For speed-relevant code a carefully implemented use of
|
||||
* GET_UTF8() may be preferred.
|
||||
*
|
||||
* @param codep pointer used to return the parsed code in case of success.
|
||||
* The value in *codep is set even in case the range check fails.
|
||||
* @param bufp pointer to the address the first byte of the sequence
|
||||
* to decode, updated by the function to point to the
|
||||
* byte next after the decoded sequence
|
||||
* @param buf_end pointer to the end of the buffer, points to the next
|
||||
* byte past the last in the buffer. This is used to
|
||||
* avoid buffer overreads (in case of an unfinished
|
||||
* UTF-8 sequence towards the end of the buffer).
|
||||
* @param flags a collection of AV_UTF8_FLAG_* flags
|
||||
* @return >= 0 in case a sequence was successfully read, a negative
|
||||
* value in case of invalid sequence
|
||||
*/
|
||||
av_warn_unused_result
|
||||
int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end,
|
||||
unsigned int flags);
|
||||
|
||||
/**
|
||||
* Check if a name is in a list.
|
||||
* @returns 0 if not found, or the 1 based index where it has been found in the
|
||||
* list.
|
||||
*/
|
||||
int av_match_list(const char *name, const char *list, char separator);
|
||||
|
||||
/**
|
||||
* See libc sscanf manual for more information.
|
||||
* Locale-independent sscanf implementation.
|
||||
*/
|
||||
int av_sscanf(const char *string, const char *format, ...);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_AVSTRING_H */
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_AVUTIL_H
|
||||
#define AVUTIL_AVUTIL_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavu
|
||||
* Convenience header that includes @ref lavu "libavutil"'s core.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage
|
||||
*
|
||||
* @section ffmpeg_intro Introduction
|
||||
*
|
||||
* This document describes the usage of the different libraries
|
||||
* provided by FFmpeg.
|
||||
*
|
||||
* @li @ref libavc "libavcodec" encoding/decoding library
|
||||
* @li @ref lavfi "libavfilter" graph-based frame editing library
|
||||
* @li @ref libavf "libavformat" I/O and muxing/demuxing library
|
||||
* @li @ref lavd "libavdevice" special devices muxing/demuxing library
|
||||
* @li @ref lavu "libavutil" common utility library
|
||||
* @li @ref lswr "libswresample" audio resampling, format conversion and mixing
|
||||
* @li @ref lpp "libpostproc" post processing library
|
||||
* @li @ref libsws "libswscale" color conversion and scaling library
|
||||
*
|
||||
* @section ffmpeg_versioning Versioning and compatibility
|
||||
*
|
||||
* Each of the FFmpeg libraries contains a version.h header, which defines a
|
||||
* major, minor and micro version number with the
|
||||
* <em>LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO}</em> macros. The major version
|
||||
* number is incremented with backward incompatible changes - e.g. removing
|
||||
* parts of the public API, reordering public struct members, etc. The minor
|
||||
* version number is incremented for backward compatible API changes or major
|
||||
* new features - e.g. adding a new public function or a new decoder. The micro
|
||||
* version number is incremented for smaller changes that a calling program
|
||||
* might still want to check for - e.g. changing behavior in a previously
|
||||
* unspecified situation.
|
||||
*
|
||||
* FFmpeg guarantees backward API and ABI compatibility for each library as long
|
||||
* as its major version number is unchanged. This means that no public symbols
|
||||
* will be removed or renamed. Types and names of the public struct members and
|
||||
* values of public macros and enums will remain the same (unless they were
|
||||
* explicitly declared as not part of the public API). Documented behavior will
|
||||
* not change.
|
||||
*
|
||||
* In other words, any correct program that works with a given FFmpeg snapshot
|
||||
* should work just as well without any changes with any later snapshot with the
|
||||
* same major versions. This applies to both rebuilding the program against new
|
||||
* FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program
|
||||
* links against.
|
||||
*
|
||||
* However, new public symbols may be added and new members may be appended to
|
||||
* public structs whose size is not part of public ABI (most public structs in
|
||||
* FFmpeg). New macros and enum values may be added. Behavior in undocumented
|
||||
* situations may change slightly (and be documented). All those are accompanied
|
||||
* by an entry in doc/APIchanges and incrementing either the minor or micro
|
||||
* version number.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup lavu libavutil
|
||||
* Common code shared across all FFmpeg libraries.
|
||||
*
|
||||
* @note
|
||||
* libavutil is designed to be modular. In most cases, in order to use the
|
||||
* functions provided by one component of libavutil you must explicitly include
|
||||
* the specific header containing that feature. If you are only using
|
||||
* media-related components, you could simply include libavutil/avutil.h, which
|
||||
* brings in most of the "core" components.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @defgroup lavu_crypto Crypto and Hashing
|
||||
*
|
||||
* @{
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_math Mathematics
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_string String Manipulation
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_mem Memory Management
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_data Data Structures
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_video Video related
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_audio Audio related
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_error Error Codes
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_log Logging Facility
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup lavu_misc Other
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @defgroup preproc_misc Preprocessor String Macros
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*
|
||||
* @defgroup version_utils Library Version Macros
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup lavu_ver
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return the LIBAVUTIL_VERSION_INT constant.
|
||||
*/
|
||||
unsigned avutil_version(void);
|
||||
|
||||
/**
|
||||
* Return an informative version string. This usually is the actual release
|
||||
* version number or a git commit description. This string has no fixed format
|
||||
* and can change any time. It should never be parsed by code.
|
||||
*/
|
||||
const char *av_version_info(void);
|
||||
|
||||
/**
|
||||
* Return the libavutil build-time configuration.
|
||||
*/
|
||||
const char *avutil_configuration(void);
|
||||
|
||||
/**
|
||||
* Return the libavutil license.
|
||||
*/
|
||||
const char *avutil_license(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup lavu_media Media Type
|
||||
* @brief Media Type
|
||||
*/
|
||||
|
||||
enum AVMediaType {
|
||||
AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA
|
||||
AVMEDIA_TYPE_VIDEO,
|
||||
AVMEDIA_TYPE_AUDIO,
|
||||
AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous
|
||||
AVMEDIA_TYPE_SUBTITLE,
|
||||
AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse
|
||||
AVMEDIA_TYPE_NB
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a string describing the media_type enum, NULL if media_type
|
||||
* is unknown.
|
||||
*/
|
||||
const char *av_get_media_type_string(enum AVMediaType media_type);
|
||||
|
||||
/**
|
||||
* @defgroup lavu_const Constants
|
||||
* @{
|
||||
*
|
||||
* @defgroup lavu_enc Encoding specific
|
||||
*
|
||||
* @note those definition should move to avcodec
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define FF_LAMBDA_SHIFT 7
|
||||
#define FF_LAMBDA_SCALE (1<<FF_LAMBDA_SHIFT)
|
||||
#define FF_QP2LAMBDA 118 ///< factor to convert from H.263 QP to lambda
|
||||
#define FF_LAMBDA_MAX (256*128-1)
|
||||
|
||||
#define FF_QUALITY_SCALE FF_LAMBDA_SCALE //FIXME maybe remove
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @defgroup lavu_time Timestamp specific
|
||||
*
|
||||
* FFmpeg internal timebase and timestamp definitions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Undefined timestamp value
|
||||
*
|
||||
* Usually reported by demuxer that work on containers that do not provide
|
||||
* either pts or dts.
|
||||
*/
|
||||
|
||||
#define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000))
|
||||
|
||||
/**
|
||||
* Internal time base represented as integer
|
||||
*/
|
||||
|
||||
#define AV_TIME_BASE 1000000
|
||||
|
||||
/**
|
||||
* Internal time base represented as fractional value
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* ISO C++ forbids compound-literals. */
|
||||
#define AV_TIME_BASE_Q av_make_q(1, AV_TIME_BASE)
|
||||
#else
|
||||
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
* @defgroup lavu_picture Image related
|
||||
*
|
||||
* AVPicture types, pixel formats and basic image planes manipulation.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
enum AVPictureType {
|
||||
AV_PICTURE_TYPE_NONE = 0, ///< Undefined
|
||||
AV_PICTURE_TYPE_I, ///< Intra
|
||||
AV_PICTURE_TYPE_P, ///< Predicted
|
||||
AV_PICTURE_TYPE_B, ///< Bi-dir predicted
|
||||
AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG-4
|
||||
AV_PICTURE_TYPE_SI, ///< Switching Intra
|
||||
AV_PICTURE_TYPE_SP, ///< Switching Predicted
|
||||
AV_PICTURE_TYPE_BI, ///< BI type
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a single letter to describe the given picture type
|
||||
* pict_type.
|
||||
*
|
||||
* @param[in] pict_type the picture type @return a single character
|
||||
* representing the picture type, '?' if pict_type is unknown
|
||||
*/
|
||||
char av_get_picture_type_char(enum AVPictureType pict_type);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "rational.h"
|
||||
#include "version.h"
|
||||
#include "macros.h"
|
||||
#include "mathematics.h"
|
||||
#include "log.h"
|
||||
#include "pixfmt.h"
|
||||
|
||||
/**
|
||||
* Return x default pointer in case p is NULL.
|
||||
*/
|
||||
static inline void *av_x_if_null(const void *p, const void *x)
|
||||
{
|
||||
return (void *)(intptr_t)(p ? p : x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the length of an integer list.
|
||||
*
|
||||
* @param elsize size in bytes of each list element (only 1, 2, 4 or 8)
|
||||
* @param term list terminator (usually 0 or -1)
|
||||
* @param list pointer to the list
|
||||
* @return length of the list, in elements, not counting the terminator
|
||||
*/
|
||||
unsigned av_int_list_length_for_size(unsigned elsize,
|
||||
const void *list, uint64_t term) av_pure;
|
||||
|
||||
/**
|
||||
* Compute the length of an integer list.
|
||||
*
|
||||
* @param term list terminator (usually 0 or -1)
|
||||
* @param list pointer to the list
|
||||
* @return length of the list, in elements, not counting the terminator
|
||||
*/
|
||||
#define av_int_list_length(list, term) \
|
||||
av_int_list_length_for_size(sizeof(*(list)), list, term)
|
||||
|
||||
/**
|
||||
* Return the fractional representation of the internal time base.
|
||||
*/
|
||||
AVRational av_get_time_base_q(void);
|
||||
|
||||
#define AV_FOURCC_MAX_STRING_SIZE 32
|
||||
|
||||
#define av_fourcc2str(fourcc) av_fourcc_make_string((char[AV_FOURCC_MAX_STRING_SIZE]){0}, fourcc)
|
||||
|
||||
/**
|
||||
* Fill the provided buffer with a string containing a FourCC (four-character
|
||||
* code) representation.
|
||||
*
|
||||
* @param buf a buffer with size in bytes of at least AV_FOURCC_MAX_STRING_SIZE
|
||||
* @param fourcc the fourcc to represent
|
||||
* @return the buffer in input
|
||||
*/
|
||||
char *av_fourcc_make_string(char *buf, uint32_t fourcc);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_AVUTIL_H */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_BASE64_H
|
||||
#define AVUTIL_BASE64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @defgroup lavu_base64 Base64
|
||||
* @ingroup lavu_crypto
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decode a base64-encoded string.
|
||||
*
|
||||
* @param out buffer for decoded data
|
||||
* @param in null-terminated input string
|
||||
* @param out_size size in bytes of the out buffer, must be at
|
||||
* least 3/4 of the length of in, that is AV_BASE64_DECODE_SIZE(strlen(in))
|
||||
* @return number of bytes written, or a negative value in case of
|
||||
* invalid input
|
||||
*/
|
||||
int av_base64_decode(uint8_t *out, const char *in, int out_size);
|
||||
|
||||
/**
|
||||
* Calculate the output size in bytes needed to decode a base64 string
|
||||
* with length x to a data buffer.
|
||||
*/
|
||||
#define AV_BASE64_DECODE_SIZE(x) ((x) * 3LL / 4)
|
||||
|
||||
/**
|
||||
* Encode data to base64 and null-terminate.
|
||||
*
|
||||
* @param out buffer for encoded data
|
||||
* @param out_size size in bytes of the out buffer (including the
|
||||
* null terminator), must be at least AV_BASE64_SIZE(in_size)
|
||||
* @param in input buffer containing the data to encode
|
||||
* @param in_size size in bytes of the in buffer
|
||||
* @return out or NULL in case of error
|
||||
*/
|
||||
char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size);
|
||||
|
||||
/**
|
||||
* Calculate the output size needed to base64-encode x bytes to a
|
||||
* null-terminated string.
|
||||
*/
|
||||
#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_BASE64_H */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Blowfish algorithm
|
||||
* Copyright (c) 2012 Samuel Pitoiset
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_BLOWFISH_H
|
||||
#define AVUTIL_BLOWFISH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @defgroup lavu_blowfish Blowfish
|
||||
* @ingroup lavu_crypto
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define AV_BF_ROUNDS 16
|
||||
|
||||
typedef struct AVBlowfish {
|
||||
uint32_t p[AV_BF_ROUNDS + 2];
|
||||
uint32_t s[4][256];
|
||||
} AVBlowfish;
|
||||
|
||||
/**
|
||||
* Allocate an AVBlowfish context.
|
||||
*/
|
||||
AVBlowfish *av_blowfish_alloc(void);
|
||||
|
||||
/**
|
||||
* Initialize an AVBlowfish context.
|
||||
*
|
||||
* @param ctx an AVBlowfish context
|
||||
* @param key a key
|
||||
* @param key_len length of the key
|
||||
*/
|
||||
void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len);
|
||||
|
||||
/**
|
||||
* Encrypt or decrypt a buffer using a previously initialized context.
|
||||
*
|
||||
* @param ctx an AVBlowfish context
|
||||
* @param xl left four bytes halves of input to be encrypted
|
||||
* @param xr right four bytes halves of input to be encrypted
|
||||
* @param decrypt 0 for encryption, 1 for decryption
|
||||
*/
|
||||
void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr,
|
||||
int decrypt);
|
||||
|
||||
/**
|
||||
* Encrypt or decrypt a buffer using a previously initialized context.
|
||||
*
|
||||
* @param ctx an AVBlowfish context
|
||||
* @param dst destination array, can be equal to src
|
||||
* @param src source array, can be equal to dst
|
||||
* @param count number of 8 byte blocks
|
||||
* @param iv initialization vector for CBC mode, if NULL ECB will be used
|
||||
* @param decrypt 0 for encryption, 1 for decryption
|
||||
*/
|
||||
void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src,
|
||||
int count, uint8_t *iv, int decrypt);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* AVUTIL_BLOWFISH_H */
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Nicolas George
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @ingroup lavu_avbprint
|
||||
* AVBPrint public header
|
||||
*/
|
||||
|
||||
#ifndef AVUTIL_BPRINT_H
|
||||
#define AVUTIL_BPRINT_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "attributes.h"
|
||||
#include "avstring.h"
|
||||
|
||||
/**
|
||||
* @defgroup lavu_avbprint AVBPrint
|
||||
* @ingroup lavu_data
|
||||
*
|
||||
* A buffer to print data progressively
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Define a structure with extra padding to a fixed size
|
||||
* This helps ensuring binary compatibility with future versions.
|
||||
*/
|
||||
|
||||
#define FF_PAD_STRUCTURE(name, size, ...) \
|
||||
struct ff_pad_helper_##name { __VA_ARGS__ }; \
|
||||
typedef struct name { \
|
||||
__VA_ARGS__ \
|
||||
char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \
|
||||
} name;
|
||||
|
||||
/**
|
||||
* Buffer to print data progressively
|
||||
*
|
||||
* The string buffer grows as necessary and is always 0-terminated.
|
||||
* The content of the string is never accessed, and thus is
|
||||
* encoding-agnostic and can even hold binary data.
|
||||
*
|
||||
* Small buffers are kept in the structure itself, and thus require no
|
||||
* memory allocation at all (unless the contents of the buffer is needed
|
||||
* after the structure goes out of scope). This is almost as lightweight as
|
||||
* declaring a local `char buf[512]`.
|
||||
*
|
||||
* The length of the string can go beyond the allocated size: the buffer is
|
||||
* then truncated, but the functions still keep account of the actual total
|
||||
* length.
|
||||
*
|
||||
* In other words, AVBPrint.len can be greater than AVBPrint.size and records
|
||||
* the total length of what would have been to the buffer if there had been
|
||||
* enough memory.
|
||||
*
|
||||
* Append operations do not need to be tested for failure: if a memory
|
||||
* allocation fails, data stop being appended to the buffer, but the length
|
||||
* is still updated. This situation can be tested with
|
||||
* av_bprint_is_complete().
|
||||
*
|
||||
* The AVBPrint.size_max field determines several possible behaviours:
|
||||
* - `size_max = -1` (= `UINT_MAX`) or any large value will let the buffer be
|
||||
* reallocated as necessary, with an amortized linear cost.
|
||||
* - `size_max = 0` prevents writing anything to the buffer: only the total
|
||||
* length is computed. The write operations can then possibly be repeated in
|
||||
* a buffer with exactly the necessary size
|
||||
* (using `size_init = size_max = len + 1`).
|
||||
* - `size_max = 1` is automatically replaced by the exact size available in the
|
||||
* structure itself, thus ensuring no dynamic memory allocation. The
|
||||
* internal buffer is large enough to hold a reasonable paragraph of text,
|
||||
* such as the current paragraph.
|
||||
*/
|
||||
|
||||
FF_PAD_STRUCTURE(AVBPrint, 1024,
|
||||
char *str; /**< string so far */
|
||||
unsigned len; /**< length so far */
|
||||
unsigned size; /**< allocated memory */
|
||||
unsigned size_max; /**< maximum allocated memory */
|
||||
char reserved_internal_buffer[1];
|
||||
)
|
||||
|
||||
/**
|
||||
* @name Max size special values
|
||||
* Convenience macros for special values for av_bprint_init() size_max
|
||||
* parameter.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Buffer will be reallocated as necessary, with an amortized linear cost.
|
||||
*/
|
||||
#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1)
|
||||
/**
|
||||
* Use the exact size available in the AVBPrint structure itself.
|
||||
*
|
||||
* Thus ensuring no dynamic memory allocation. The internal buffer is large
|
||||
* enough to hold a reasonable paragraph of text, such as the current paragraph.
|
||||
*/
|
||||
#define AV_BPRINT_SIZE_AUTOMATIC 1
|
||||
/**
|
||||
* Do not write anything to the buffer, only calculate the total length.
|
||||
*
|
||||
* The write operations can then possibly be repeated in a buffer with
|
||||
* exactly the necessary size (using `size_init = size_max = AVBPrint.len + 1`).
|
||||
*/
|
||||
#define AV_BPRINT_SIZE_COUNT_ONLY 0
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Init a print buffer.
|
||||
*
|
||||
* @param buf buffer to init
|
||||
* @param size_init initial size (including the final 0)
|
||||
* @param size_max maximum size;
|
||||
* - `0` means do not write anything, just count the length
|
||||
* - `1` is replaced by the maximum value for automatic storage
|
||||
* any large value means that the internal buffer will be
|
||||
* reallocated as needed up to that limit
|
||||
* - `-1` is converted to `UINT_MAX`, the largest limit possible.
|
||||
* Check also `AV_BPRINT_SIZE_*` macros.
|
||||
*/
|
||||
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
|
||||
|
||||
/**
|
||||
* Init a print buffer using a pre-existing buffer.
|
||||
*
|
||||
* The buffer will not be reallocated.
|
||||
* In case size equals zero, the AVBPrint will be initialized to use
|
||||
* the internal buffer as if using AV_BPRINT_SIZE_COUNT_ONLY with
|
||||
* av_bprint_init().
|
||||
*
|
||||
* @param buf buffer structure to init
|
||||
* @param buffer byte buffer to use for the string data
|
||||
* @param size size of buffer
|
||||
*/
|
||||
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size);
|
||||
|
||||
/**
|
||||
* Append a formatted string to a print buffer.
|
||||
*/
|
||||
void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
|
||||
|
||||
/**
|
||||
* Append a formatted string to a print buffer.
|
||||
*/
|
||||
void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg);
|
||||
|
||||
/**
|
||||
* Append char c n times to a print buffer.
|
||||
*/
|
||||
void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
|
||||
|
||||
/**
|
||||
* Append data to a print buffer.
|
||||
*
|
||||
* @param buf bprint buffer to use
|
||||
* @param data pointer to data
|
||||
* @param size size of data
|
||||
*/
|
||||
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size);
|
||||
|
||||
struct tm;
|
||||
/**
|
||||
* Append a formatted date and time to a print buffer.
|
||||
*
|
||||
* @param buf bprint buffer to use
|
||||
* @param fmt date and time format string, see strftime()
|
||||
* @param tm broken-down time structure to translate
|
||||
*
|
||||
* @note due to poor design of the standard strftime function, it may
|
||||
* produce poor results if the format string expands to a very long text and
|
||||
* the bprint buffer is near the limit stated by the size_max option.
|
||||
*/
|
||||
void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm);
|
||||
|
||||
/**
|
||||
* Allocate bytes in the buffer for external use.
|
||||
*
|
||||
* @param[in] buf buffer structure
|
||||
* @param[in] size required size
|
||||
* @param[out] mem pointer to the memory area
|
||||
* @param[out] actual_size size of the memory area after allocation;
|
||||
* can be larger or smaller than size
|
||||
*/
|
||||
void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
|
||||
unsigned char **mem, unsigned *actual_size);
|
||||
|
||||
/**
|
||||
* Reset the string to "" but keep internal allocated data.
|
||||
*/
|
||||
void av_bprint_clear(AVBPrint *buf);
|
||||
|
||||
/**
|
||||
* Test if the print buffer is complete (not truncated).
|
||||
*
|
||||
* It may have been truncated due to a memory allocation failure
|
||||
* or the size_max limit (compare size and size_max if necessary).
|
||||
*/
|
||||
static inline int av_bprint_is_complete(const AVBPrint *buf)
|
||||
{
|
||||
return buf->len < buf->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize a print buffer.
|
||||
*
|
||||
* The print buffer can no longer be used afterwards,
|
||||
* but the len and size fields are still valid.
|
||||
*
|
||||
* @arg[out] ret_str if not NULL, used to return a permanent copy of the
|
||||
* buffer contents, or NULL if memory allocation fails;
|
||||
* if NULL, the buffer is discarded and freed
|
||||
* @return 0 for success or error code (probably AVERROR(ENOMEM))
|
||||
*/
|
||||
int av_bprint_finalize(AVBPrint *buf, char **ret_str);
|
||||
|
||||
/**
|
||||
* Escape the content in src and append it to dstbuf.
|
||||
*
|
||||
* @param dstbuf already inited destination bprint buffer
|
||||
* @param src string containing the text to escape
|
||||
* @param special_chars string containing the special characters which
|
||||
* need to be escaped, can be NULL
|
||||
* @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
|
||||
* Any unknown value for mode will be considered equivalent to
|
||||
* AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
|
||||
* notice.
|
||||
* @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros
|
||||
*/
|
||||
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
|
||||
enum AVEscapeMode mode, int flags);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* AVUTIL_BPRINT_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user