Compare commits

..
144 Commits
Author SHA1 Message Date
lun_admin d73a1dda56 ... 2026-08-18 11:28:54 +09:00
lun_admin 2177452f52 .. 2026-08-12 18:08:18 +09:00
lun_admin b526fe4670 ... 2026-08-12 17:20:03 +09:00
lun_admin 1f696902da ... 2026-08-12 15:18:33 +09:00
lun_admin 14e26702c1 ... 2026-08-10 17:24:04 +09:00
lun_admin ad505863b7 ... 2026-08-03 17:52:49 +09:00
lun_admin 24a2a74768 .. 2026-07-09 17:29:23 +09:00
lun_admin 278c1b4510 .. 2026-07-09 16:47:21 +09:00
lun_admin dab91b1a65 ... 2026-06-30 10:00:31 +09:00
lun_admin 0400385cf8 ... 2026-06-08 14:45:38 +09:00
lun_admin 378f6495be .. 2026-05-20 17:57:56 +09:00
lun_admin 257ddb6776 ... 2026-04-30 17:28:30 +09:00
lun_admin c5d0a827e9 ... 2026-04-21 17:10:59 +09:00
lun_admin b64df76c90 ... 2026-04-21 16:36:43 +09:00
lun_admin ac1c0b12b3 ... 2026-04-21 15:37:32 +09:00
lun_admin fd0ee96c04 ... 2026-04-21 14:02:33 +09:00
lun_admin c8000d022c ... 2026-04-20 18:09:43 +09:00
lun_admin 5b86fc7e2b ... 2026-04-20 17:48:09 +09:00
lun_admin 6813a6bdd7 /... 2026-04-20 17:10:15 +09:00
lun_admin 5ded732345 ... 2026-04-15 15:04:20 +09:00
lun_admin fa5e6bbedc s 2026-04-12 23:43:58 +09:00
lun_admin d0422fafeb .. 2026-04-11 17:32:14 +09:00
lun_admin 2327326cca ... 2026-04-10 15:48:16 +09:00
lun_admin 162d2b7563 ... 2026-04-10 15:31:07 +09:00
lun_admin 964655af7f . 2026-04-09 21:19:09 +09:00
lun_admin 0405629106 .... 2026-04-09 18:24:49 +09:00
lun_admin f9e8c3de37 ... 2026-04-09 17:31:08 +09:00
lun_admin 1da8d5bb62 ... 2026-04-09 17:16:23 +09:00
lun_admin 5e7c121cf8 .. 2026-04-08 17:25:14 +09:00
lun_admin 274eaa3213 .... 2026-04-08 16:11:52 +09:00
lun_admin 80c06c5ab3 ... 2026-04-08 15:58:56 +09:00
lun_admin d7647f57e8 .. 2026-04-05 09:30:18 +09:00
lun_admin ba869e8eb4 ... 2026-04-05 09:04:46 +09:00
lun_admin 8c3bc96417 ... 2026-04-03 16:03:50 +09:00
lun_admin dc19ff5339 ... 2026-04-02 18:18:11 +09:00
lun_admin e9e585bad0 ... 2026-04-01 17:59:30 +09:00
lun_admin 9526104a4a .. 2026-04-01 11:12:06 +09:00
lun_admin 92d228d2e0 ... 2026-03-31 18:15:28 +09:00
lun_admin 5a8e2293ca ... 2026-03-31 11:38:44 +09:00
lun_admin 2ed5957365 ... 2026-03-30 14:49:08 +09:00
lun_admin 86f387b2fa ... 2026-03-30 14:28:54 +09:00
lun_admin 57039939fd ... 2026-03-30 14:10:05 +09:00
lun_admin 416279a11f Merge branch 'main' of https://dev.lunaticbum.kr/lun_admin/android_multiviewwer
# Conflicts:
#	app/src/main/kotlin/bums/lunatic/launcher/workers/TorrentManager.kt
2026-03-30 11:20:57 +09:00
lun_admin 10fddc35d3 ... 2026-03-30 11:13:29 +09:00
lun_admin e056e68808 ... 2026-03-29 09:18:56 +09:00
lun_admin a5c0bd67a8 .. 2026-03-29 08:40:59 +09:00
lun_admin a7df635f66 ... 2026-03-27 18:08:08 +09:00
lun_admin 99e1d49a4b ... 2026-03-26 18:12:30 +09:00
lun_admin cca0d282d6 ... 2026-03-26 17:24:22 +09:00
lun_admin cd8deba1f9 .. 2026-03-26 16:57:11 +09:00
lun_admin b0dbaa50df .. 2026-03-26 15:01:11 +09:00
lun_admin 466a819800 ... 2026-03-24 18:17:18 +09:00
lun_admin 68c16339ea .... 2026-03-24 15:53:29 +09:00
lun_admin 112012ce0c ... 2026-03-23 18:03:45 +09:00
lun_admin 9aee32e42d ... 2026-03-23 14:53:26 +09:00
lun_admin a8c7641e69 ... 2026-03-23 12:05:55 +09:00
lun_admin 996a75fc3e ... 2026-03-20 18:13:58 +09:00
lun_admin 3f0a7d0d5c .. 2026-03-20 17:55:48 +09:00
lun_admin 406e7820bc ... 2026-03-19 18:15:08 +09:00
lun_admin d4ec1d5652 ... 2026-03-19 14:55:22 +09:00
lun_admin 1383781dc6 ... 2026-03-16 15:22:49 +09:00
lun_admin a9fdf9ac9f .. 2026-03-13 10:41:36 +09:00
lun_admin a72b1778a9 ... 2026-03-12 17:09:35 +09:00
lun_admin be016409d7 .. 2026-03-10 17:45:28 +09:00
lun_admin 3fefb5476f ... 2026-03-05 18:22:08 +09:00
lun_admin 1ba808fcf0 .... 2026-03-05 18:15:42 +09:00
lun_admin 70869d7e1e ... 2026-03-05 18:11:08 +09:00
lun_admin 83546e5e10 ... 2026-03-04 18:00:00 +09:00
lun_admin 614e244be7 ... 2026-03-04 16:39:49 +09:00
lun_admin b73fbf2160 ... 2026-02-24 19:15:59 +09:00
lun_admin 33a4674a82 ... 2026-02-24 19:13:34 +09:00
lun_admin 5052d5cf52 .. 2026-02-24 18:04:59 +09:00
lun_admin 768dd0ebf0 ... 2026-02-24 13:30:16 +09:00
lun_admin c80e173ad9 ... 2026-02-12 16:38:08 +09:00
lun_admin 764025f1e7 ... 2026-02-05 18:16:20 +09:00
lun_admin 98d4d3e463 .. 2026-02-04 17:49:36 +09:00
lun_admin 4f389dea45 .. 2026-02-03 18:16:06 +09:00
lun_admin 12c135dc95 ... 2026-02-03 18:07:00 +09:00
lun_admin cfe4686cef ..... 2026-01-30 17:26:10 +09:00
lun_admin 9f6c424e04 ... 2026-01-30 16:52:36 +09:00
lun_admin 16640559b3 ... 2026-01-26 15:32:30 +09:00
lun_admin e61fa99c98 .. 2026-01-19 17:10:02 +09:00
lun_admin 5425589ad9 ... 2026-01-14 17:27:56 +09:00
lun_admin 175165184d 일단 저장 2026-01-13 18:04:06 +09:00
lun_admin df69d779d9 ... 2026-01-12 15:57:02 +09:00
lun_admin 6e7e9685ab ... 2026-01-12 13:58:11 +09:00
lun_admin f21f96f8a3 . 2026-01-09 17:56:28 +09:00
lun_admin 98fd382ed4 .. 2026-01-09 16:36:43 +09:00
lun_admin 62f1e646ab ,,,.... 2026-01-08 18:20:30 +09:00
lun_admin dc6b95108f .. 2026-01-07 18:13:43 +09:00
lun_admin 578f3f96ad .. 2025-12-29 18:11:39 +09:00
lun_admin 773796d36a ... 2025-10-20 17:20:16 +09:00
lun_admin 401387bd00 .. 2025-10-17 18:14:26 +09:00
lun_admin e9b287cf81 .. 2025-10-13 18:57:22 +09:00
lun_admin 197d704e27 ... 2025-09-23 18:03:47 +09:00
lun_admin a4e21be0ec ... 2025-09-23 15:37:38 +09:00
lun_admin f794e24f24 ... 2025-09-19 18:08:03 +09:00
lun_admin 5670ece56d ... 2025-09-18 17:55:44 +09:00
lun_admin c90b660429 .. 2025-09-12 18:09:25 +09:00
lun_admin ca3527bc17 ... 2025-09-08 18:21:36 +09:00
lun_admin 37a6497c84 ... 2025-09-08 18:06:53 +09:00
lun_admin b5bbf299bd .. 2025-09-07 23:14:03 +09:00
lun_admin 520350f9d1 ... 2025-08-31 13:07:04 +09:00
lun_admin 32e38fda59 ... 2025-08-29 18:01:53 +09:00
lun_admin 03086981e5 ㅇㅇ 2025-08-29 16:00:24 +09:00
lun_admin 167c433a59 ... 2025-08-28 18:23:59 +09:00
lun_admin af80e71d17 ... 2025-08-28 18:13:46 +09:00
lun_admin 9dd1276aa1 ... 2025-08-28 17:43:36 +09:00
lun_admin 6404f4176e ... 2025-08-28 15:13:40 +09:00
lun_admin 6e64d739ac .. 2025-08-27 18:19:26 +09:00
lun_admin a13f66d917 ... 2025-08-27 15:09:05 +09:00
lun_admin 57961d84de ... 2025-08-26 18:24:06 +09:00
lun_admin 87fa624983 ... 2025-08-26 13:32:53 +09:00
lun_admin 1e06d82015 ... 2025-08-25 18:17:27 +09:00
lun_admin e646a72418 ... 2025-08-25 15:20:30 +09:00
lun_admin 6c4d7e68f6 .. 2025-08-25 09:45:58 +09:00
lun_admin fd0d61c584 ... 2025-08-22 17:06:04 +09:00
lun_admin a11e40c56c ... 2025-08-22 15:01:17 +09:00
lun_admin 4acc01b742 .... 2025-08-22 13:06:45 +09:00
lun_admin 53ba35a3de ... 2025-08-21 17:30:09 +09:00
lun_admin 634d703572 ... 2025-08-21 17:20:03 +09:00
lun_admin 2f63f8550a ... 2025-08-20 17:08:17 +09:00
lun_admin f7f71ca195 /// 2025-08-18 18:44:11 +09:00
lun_admin b34750099e ... 2025-08-18 18:24:19 +09:00
lun_admin 44ac92ca17 . 2025-08-17 16:19:58 +09:00
lun_admin 5c7325843c ... 2025-08-17 16:17:52 +09:00
lun_admin c2e4e01036 .... 2025-08-14 18:11:50 +09:00
lun_admin ed8b691452 ... 2025-08-14 16:48:48 +09:00
lun_admin 068a7bd8e2 .. 2025-08-13 17:16:25 +09:00
lun_admin 8f3dc93ec1 .. 2025-08-13 17:02:15 +09:00
lun_admin 012fcd7b9b ... 2025-08-11 17:41:32 +09:00
lun_admin 69d93778a4 .. 2025-08-11 17:32:22 +09:00
lun_admin d1f080ded1 ... 2025-08-08 17:12:28 +09:00
lun_admin 1272c91430 ... 2025-08-01 18:36:16 +09:00
lun_admin 2a25b49baa ... 2025-07-31 10:58:58 +09:00
lun_admin 428b16cda2 ... 2025-07-27 19:37:17 +09:00
lun_admin a9cef3b40e ... 2025-07-27 19:30:12 +09:00
lun_admin 867ee66499 .. 2025-07-27 19:15:12 +09:00
lun_admin ee7cee7638 ... 2025-07-24 18:34:57 +09:00
lun_admin e979b78fb5 ... 2025-07-24 18:19:30 +09:00
lun_admin 5a6dad2f24 ... 2025-07-24 17:42:49 +09:00
lun_admin dc69070823 .. 2025-07-24 16:09:35 +09:00
lun_admin 193946cadf ... 2025-07-24 14:54:31 +09:00
lun_admin 668d33543c .. 2025-07-23 18:12:30 +09:00
3505 changed files with 805500 additions and 12697 deletions
+150 -21
View File
@@ -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
View File
@@ -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;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;amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;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;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;amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;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;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;amp;tr=http%3A%2F%2Fsukebei.tracker.wf%3A8888%2Fannounce&amp;amp;tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&amp;amp;tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&amp;amp;tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce&amp;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 &gt;&gt; </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>
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+297
View File
@@ -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_;
};
+48
View File
@@ -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_;
};
+67
View File
@@ -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}
)
+324
View File
@@ -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;
}
+77
View File
@@ -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 저장 변수 추가
};
+74
View File
@@ -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_;
}
};
+627
View File
@@ -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; }
+106
View File
@@ -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;
};
+79
View File
@@ -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;
}
+25
View File
@@ -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_;
};
+523
View File
@@ -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();
}
+108
View File
@@ -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_;
};
+141
View File
@@ -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_;
};
+39
View File
@@ -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_;
};
+15
View File
@@ -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
+103
View File
@@ -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;
}
}
+236
View File
@@ -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
+307
View File
@@ -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_ */
+168 -168
View File
@@ -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);
}
}
+250
View File
@@ -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